[1012] | 1 | #!/usr/bin/env python |
---|
| 2 | # -*- coding: utf-8 -*- |
---|
| 3 | ########### SVN repository information ################### |
---|
[1077] | 4 | # $Date: 2018-01-29 02:56:19 +0000 (Mon, 29 Jan 2018) $ |
---|
| 5 | # $Author: toby $ |
---|
| 6 | # $Revision: 3246 $ |
---|
| 7 | # $URL: trunk/exports/G2export_CIF.py $ |
---|
| 8 | # $Id: G2export_CIF.py 3246 2018-01-29 02:56:19Z toby $ |
---|
[1012] | 9 | ########### SVN repository information ################### |
---|
[1123] | 10 | ''' |
---|
| 11 | *Module G2export_CIF: CIF Exports* |
---|
| 12 | ------------------------------------------------------ |
---|
[1074] | 13 | |
---|
[1123] | 14 | This implements a complex exporter :class:`ExportCIF` that can implement an |
---|
| 15 | entire project in a complete CIF intended for submission as a |
---|
[2433] | 16 | publication. In addition, there are three subclasses of :class:`ExportCIF`: |
---|
[3011] | 17 | :class:`ExportProjectCIF`, |
---|
[2449] | 18 | :class:`ExportPhaseCIF` and :class:`ExportDataCIF` where extra parameters |
---|
| 19 | for the _Exporter() determine if a project, single phase or data set are written. |
---|
[938] | 20 | ''' |
---|
| 21 | |
---|
[3136] | 22 | from __future__ import division, print_function |
---|
| 23 | import platform |
---|
[938] | 24 | import datetime as dt |
---|
| 25 | import os.path |
---|
[1026] | 26 | import sys |
---|
[1010] | 27 | import numpy as np |
---|
[3136] | 28 | if '2' in platform.python_version_tuple()[0]: |
---|
| 29 | import cPickle as pickle |
---|
| 30 | else: |
---|
| 31 | import pickle |
---|
[1067] | 32 | import copy |
---|
[1068] | 33 | import re |
---|
[3027] | 34 | try: |
---|
| 35 | import wx |
---|
| 36 | import wx.lib.scrolledpanel as wxscroll |
---|
| 37 | import wx.lib.resizewidget as rw |
---|
| 38 | except ImportError: |
---|
| 39 | # Avoid wx dependency for CLI |
---|
| 40 | class Placeholder(object): |
---|
| 41 | def __init__(self): |
---|
| 42 | self.BoxSizer = object |
---|
| 43 | self.Button = object |
---|
| 44 | self.Dialog = object |
---|
| 45 | self.ScrolledPanel = object |
---|
| 46 | wx = Placeholder() |
---|
| 47 | wxscroll = Placeholder() |
---|
[1012] | 48 | import GSASIIpath |
---|
[1077] | 49 | GSASIIpath.SetVersionNumber("$Revision: 3246 $") |
---|
[938] | 50 | import GSASIIIO as G2IO |
---|
[3027] | 51 | try: |
---|
| 52 | import GSASIIctrlGUI as G2G |
---|
| 53 | except ImportError: |
---|
| 54 | pass |
---|
[956] | 55 | import GSASIImath as G2mth |
---|
[1013] | 56 | import GSASIIspc as G2spc |
---|
[1022] | 57 | import GSASIIstrMain as G2stMn |
---|
[3246] | 58 | import GSASIImapvars as G2mv |
---|
[956] | 59 | |
---|
[1036] | 60 | DEBUG = False #True to skip printing of reflection/powder profile lists |
---|
[1012] | 61 | |
---|
[1067] | 62 | CIFdic = None |
---|
| 63 | |
---|
[3011] | 64 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
| 65 | def WriteCIFitem(fp, name, value=''): |
---|
| 66 | '''Helper function for writing CIF output. Translated from exports/G2export_CIF.py''' |
---|
| 67 | # Ignore unicode issues |
---|
| 68 | if value: |
---|
| 69 | if "\n" in value or len(value)> 70: |
---|
| 70 | if name.strip(): |
---|
| 71 | fp.write(name+'\n') |
---|
| 72 | fp.write('; '+value+'\n') |
---|
| 73 | fp.write('; '+'\n') |
---|
| 74 | elif " " in value: |
---|
| 75 | if len(name)+len(value) > 65: |
---|
| 76 | fp.write(name + '\n ' + '"' + str(value) + '"'+'\n') |
---|
| 77 | else: |
---|
| 78 | fp.write(name + ' ' + '"' + str(value) + '"'+'\n') |
---|
| 79 | else: |
---|
| 80 | if len(name)+len(value) > 65: |
---|
| 81 | fp.write(name+'\n ' + value+'\n') |
---|
| 82 | else: |
---|
| 83 | fp.write(name+' ' + value+'\n') |
---|
| 84 | else: |
---|
| 85 | fp.write(name+'\n') |
---|
| 86 | |
---|
| 87 | |
---|
| 88 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
| 89 | def WriteAtomsNuclear(fp, phasedict, phasenam, parmDict, sigDict, labellist): |
---|
| 90 | 'Write atom positions to CIF' |
---|
| 91 | # phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
| 92 | General = phasedict['General'] |
---|
| 93 | cx,ct,cs,cia = General['AtomPtrs'] |
---|
| 94 | Atoms = phasedict['Atoms'] |
---|
| 95 | cfrac = cx+3 |
---|
| 96 | fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
| 97 | for i,at in enumerate(Atoms): |
---|
| 98 | fval = parmDict.get(fpfx+str(i),at[cfrac]) |
---|
| 99 | if fval != 0.0: |
---|
| 100 | break |
---|
| 101 | else: |
---|
| 102 | WriteCIFitem(fp, '\n# PHASE HAS NO ATOMS!') |
---|
| 103 | return |
---|
| 104 | |
---|
| 105 | WriteCIFitem(fp, '\n# ATOMIC COORDINATES AND DISPLACEMENT PARAMETERS') |
---|
| 106 | WriteCIFitem(fp, 'loop_ '+ |
---|
| 107 | '\n _atom_site_label'+ |
---|
| 108 | '\n _atom_site_type_symbol'+ |
---|
| 109 | '\n _atom_site_fract_x'+ |
---|
| 110 | '\n _atom_site_fract_y'+ |
---|
| 111 | '\n _atom_site_fract_z'+ |
---|
| 112 | '\n _atom_site_occupancy'+ |
---|
| 113 | '\n _atom_site_adp_type'+ |
---|
| 114 | '\n _atom_site_U_iso_or_equiv'+ |
---|
| 115 | '\n _atom_site_symmetry_multiplicity') |
---|
| 116 | |
---|
| 117 | varnames = {cx:'Ax',cx+1:'Ay',cx+2:'Az',cx+3:'Afrac', |
---|
| 118 | cia+1:'AUiso',cia+2:'AU11',cia+3:'AU22',cia+4:'AU33', |
---|
| 119 | cia+5:'AU12',cia+6:'AU13',cia+7:'AU23'} |
---|
| 120 | # Empty the labellist |
---|
| 121 | while labellist: |
---|
| 122 | labellist.pop() |
---|
| 123 | |
---|
| 124 | pfx = str(phasedict['pId'])+'::' |
---|
| 125 | # loop over all atoms |
---|
| 126 | naniso = 0 |
---|
| 127 | for i,at in enumerate(Atoms): |
---|
| 128 | if phasedict['General']['Type'] == 'macromolecular': |
---|
| 129 | label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2]) |
---|
| 130 | s = PutInCol(MakeUniqueLabel(label,labellist),15) # label |
---|
| 131 | else: |
---|
| 132 | s = PutInCol(MakeUniqueLabel(at[ct-1],labellist),6) # label |
---|
| 133 | fval = parmDict.get(fpfx+str(i),at[cfrac]) |
---|
| 134 | if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact) |
---|
| 135 | s += PutInCol(FmtAtomType(at[ct]),4) # type |
---|
| 136 | if at[cia] == 'I': |
---|
| 137 | adp = 'Uiso ' |
---|
| 138 | else: |
---|
| 139 | adp = 'Uani ' |
---|
| 140 | naniso += 1 |
---|
| 141 | # compute Uequiv crudely |
---|
| 142 | # correct: Defined as "1/3 trace of diagonalized U matrix". |
---|
| 143 | # SEE cell2GS & Uij2Ueqv to GSASIIlattice. Former is needed to make the GS matrix used by the latter. |
---|
| 144 | t = 0.0 |
---|
| 145 | for j in (2,3,4): |
---|
| 146 | var = pfx+varnames[cia+j]+":"+str(i) |
---|
| 147 | t += parmDict.get(var,at[cia+j]) |
---|
| 148 | for j in (cx,cx+1,cx+2,cx+3,cia,cia+1): |
---|
| 149 | if j in (cx,cx+1,cx+2): |
---|
| 150 | dig = 11 |
---|
| 151 | sigdig = -0.00009 |
---|
| 152 | else: |
---|
| 153 | dig = 10 |
---|
| 154 | sigdig = -0.009 |
---|
| 155 | if j == cia: |
---|
| 156 | s += adp |
---|
| 157 | else: |
---|
| 158 | var = pfx+varnames[j]+":"+str(i) |
---|
| 159 | dvar = pfx+"d"+varnames[j]+":"+str(i) |
---|
| 160 | if dvar not in sigDict: |
---|
| 161 | dvar = var |
---|
| 162 | if j == cia+1 and adp == 'Uani ': |
---|
| 163 | val = t/3. |
---|
| 164 | sig = sigdig |
---|
| 165 | else: |
---|
| 166 | #print var,(var in parmDict),(var in sigDict) |
---|
| 167 | val = parmDict.get(var,at[j]) |
---|
| 168 | sig = sigDict.get(dvar,sigdig) |
---|
[3246] | 169 | if dvar in G2mv.GetDependentVars(): # do not include an esd for dependent vars |
---|
| 170 | sig = -abs(sig) |
---|
[3011] | 171 | s += PutInCol(G2mth.ValEsd(val,sig),dig) |
---|
| 172 | s += PutInCol(at[cs+1],3) |
---|
| 173 | WriteCIFitem(fp, s) |
---|
| 174 | if naniso == 0: return |
---|
| 175 | # now loop over aniso atoms |
---|
| 176 | WriteCIFitem(fp, '\nloop_' + '\n _atom_site_aniso_label' + |
---|
| 177 | '\n _atom_site_aniso_U_11' + '\n _atom_site_aniso_U_22' + |
---|
| 178 | '\n _atom_site_aniso_U_33' + '\n _atom_site_aniso_U_12' + |
---|
| 179 | '\n _atom_site_aniso_U_13' + '\n _atom_site_aniso_U_23') |
---|
| 180 | for i,at in enumerate(Atoms): |
---|
| 181 | fval = parmDict.get(fpfx+str(i),at[cfrac]) |
---|
| 182 | if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact) |
---|
| 183 | if at[cia] == 'I': continue |
---|
| 184 | s = PutInCol(labellist[i],6) # label |
---|
| 185 | for j in (2,3,4,5,6,7): |
---|
| 186 | sigdig = -0.0009 |
---|
| 187 | var = pfx+varnames[cia+j]+":"+str(i) |
---|
| 188 | val = parmDict.get(var,at[cia+j]) |
---|
| 189 | sig = sigDict.get(var,sigdig) |
---|
| 190 | s += PutInCol(G2mth.ValEsd(val,sig),11) |
---|
| 191 | WriteCIFitem(fp, s) |
---|
| 192 | |
---|
| 193 | |
---|
| 194 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
| 195 | def MakeUniqueLabel(lbl, labellist): |
---|
| 196 | lbl = lbl.strip() |
---|
| 197 | if not lbl: # deal with a blank label |
---|
| 198 | lbl = 'A_1' |
---|
| 199 | if lbl not in labellist: |
---|
| 200 | labellist.append(lbl) |
---|
| 201 | return lbl |
---|
| 202 | i = 1 |
---|
| 203 | prefix = lbl |
---|
| 204 | if '_' in lbl: |
---|
| 205 | prefix = lbl[:lbl.rfind('_')] |
---|
| 206 | suffix = lbl[lbl.rfind('_')+1:] |
---|
| 207 | try: |
---|
| 208 | i = int(suffix)+1 |
---|
| 209 | except: |
---|
| 210 | pass |
---|
| 211 | while prefix+'_'+str(i) in labellist: |
---|
| 212 | i += 1 |
---|
| 213 | else: |
---|
| 214 | lbl = prefix+'_'+str(i) |
---|
| 215 | labellist.append(lbl) |
---|
| 216 | |
---|
| 217 | |
---|
| 218 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
[3019] | 219 | def HillSortElements(elmlist): |
---|
| 220 | '''Sort elements in "Hill" order: C, H, others, (where others |
---|
| 221 | are alphabetical). |
---|
| 222 | |
---|
| 223 | :params list elmlist: a list of element strings |
---|
| 224 | |
---|
| 225 | :returns: a sorted list of element strings |
---|
| 226 | ''' |
---|
| 227 | newlist = [] |
---|
| 228 | oldlist = elmlist[:] |
---|
| 229 | for elm in ('C','H'): |
---|
| 230 | if elm in elmlist: |
---|
| 231 | newlist.append(elm) |
---|
| 232 | oldlist.pop(oldlist.index(elm)) |
---|
| 233 | return newlist+sorted(oldlist) |
---|
| 234 | |
---|
| 235 | |
---|
| 236 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
[3011] | 237 | def FmtAtomType(sym): |
---|
| 238 | 'Reformat a GSAS-II atom type symbol to match CIF rules' |
---|
| 239 | sym = sym.replace('_','') # underscores are not allowed: no isotope designation? |
---|
| 240 | # in CIF, oxidation state sign symbols come after, not before |
---|
| 241 | if '+' in sym: |
---|
| 242 | sym = sym.replace('+','') + '+' |
---|
| 243 | elif '-' in sym: |
---|
| 244 | sym = sym.replace('-','') + '-' |
---|
| 245 | return sym |
---|
| 246 | |
---|
| 247 | |
---|
| 248 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
| 249 | def PutInCol(val, wid): |
---|
| 250 | val = str(val).replace(' ', '') |
---|
| 251 | if not val: val = '?' |
---|
| 252 | fmt = '{:' + str(wid) + '} ' |
---|
| 253 | return fmt.format(val) |
---|
| 254 | |
---|
| 255 | |
---|
| 256 | # Refactored over here to allow access by GSASIIscriptable.py |
---|
| 257 | def WriteComposition(fp, phasedict, phasenam, parmDict): |
---|
| 258 | '''determine the composition for the unit cell, crudely determine Z and |
---|
| 259 | then compute the composition in formula units |
---|
| 260 | ''' |
---|
| 261 | General = phasedict['General'] |
---|
| 262 | Z = General.get('cellZ',0.0) |
---|
| 263 | cx,ct,cs,cia = General['AtomPtrs'] |
---|
| 264 | Atoms = phasedict['Atoms'] |
---|
| 265 | fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
| 266 | cfrac = cx+3 |
---|
| 267 | cmult = cs+1 |
---|
| 268 | compDict = {} # combines H,D & T |
---|
| 269 | sitemultlist = [] |
---|
| 270 | massDict = dict(zip(General['AtomTypes'],General['AtomMass'])) |
---|
| 271 | cellmass = 0 |
---|
| 272 | for i,at in enumerate(Atoms): |
---|
| 273 | atype = at[ct].strip() |
---|
| 274 | if atype.find('-') != -1: atype = atype.split('-')[0] |
---|
| 275 | if atype.find('+') != -1: atype = atype.split('+')[0] |
---|
| 276 | atype = atype[0].upper()+atype[1:2].lower() # force case conversion |
---|
| 277 | if atype == "D" or atype == "D": atype = "H" |
---|
| 278 | fvar = fpfx+str(i) |
---|
| 279 | fval = parmDict.get(fvar,at[cfrac]) |
---|
| 280 | mult = at[cmult] |
---|
| 281 | if not massDict.get(at[ct]): |
---|
| 282 | print('Error: No mass found for atom type '+at[ct]) |
---|
| 283 | print('Will not compute cell contents for phase '+phasenam) |
---|
| 284 | return |
---|
| 285 | cellmass += massDict[at[ct]]*mult*fval |
---|
| 286 | compDict[atype] = compDict.get(atype,0.0) + mult*fval |
---|
| 287 | if fval == 1: sitemultlist.append(mult) |
---|
| 288 | if len(compDict.keys()) == 0: return # no elements! |
---|
| 289 | if Z < 1: # Z has not been computed or set by user |
---|
| 290 | Z = 1 |
---|
| 291 | if not sitemultlist: |
---|
| 292 | General['cellZ'] = 1 |
---|
| 293 | return |
---|
| 294 | for i in range(2,min(sitemultlist)+1): |
---|
| 295 | for m in sitemultlist: |
---|
| 296 | if m % i != 0: |
---|
| 297 | break |
---|
| 298 | else: |
---|
| 299 | Z = i |
---|
| 300 | General['cellZ'] = Z # save it |
---|
| 301 | |
---|
| 302 | # when scattering factors are included in the CIF, this needs to be |
---|
| 303 | # added to the loop here but only in the one-block case. |
---|
| 304 | # For multiblock CIFs, scattering factors go in the histogram |
---|
| 305 | # blocks (for all atoms in all appropriate phases) - an example?: |
---|
| 306 | #loop_ |
---|
| 307 | # _atom_type_symbol |
---|
| 308 | # _atom_type_description |
---|
| 309 | # _atom_type_scat_dispersion_real |
---|
| 310 | # _atom_type_scat_dispersion_imag |
---|
| 311 | # _atom_type_scat_source |
---|
| 312 | # 'C' 'C' 0.0033 0.0016 |
---|
| 313 | # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 314 | # 'H' 'H' 0.0000 0.0000 |
---|
| 315 | # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 316 | # 'P' 'P' 0.1023 0.0942 |
---|
| 317 | # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 318 | # 'Cl' 'Cl' 0.1484 0.1585 |
---|
| 319 | # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 320 | # 'Cu' 'Cu' 0.3201 1.2651 |
---|
| 321 | # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 322 | |
---|
| 323 | #if oneblock: # add scattering factors for current phase here |
---|
| 324 | WriteCIFitem(fp, '\nloop_ _atom_type_symbol _atom_type_number_in_cell') |
---|
| 325 | formula = '' |
---|
| 326 | reload(G2mth) |
---|
| 327 | for elem in HillSortElements(compDict.keys()): |
---|
| 328 | WriteCIFitem(fp, ' ' + PutInCol(elem,4) + |
---|
| 329 | G2mth.ValEsd(compDict[elem],-0.009,True)) |
---|
| 330 | if formula: formula += " " |
---|
| 331 | formula += elem |
---|
| 332 | if compDict[elem] == Z: continue |
---|
| 333 | formula += G2mth.ValEsd(compDict[elem]/Z,-0.009,True) |
---|
| 334 | WriteCIFitem(fp, '\n# Note that Z affects _cell_formula_sum and _weight') |
---|
| 335 | WriteCIFitem(fp, '_cell_formula_units_Z',str(Z)) |
---|
| 336 | WriteCIFitem(fp, '_chemical_formula_sum',formula) |
---|
| 337 | WriteCIFitem(fp, '_chemical_formula_weight', |
---|
| 338 | G2mth.ValEsd(cellmass/Z,-0.09,True)) |
---|
| 339 | |
---|
[3019] | 340 | |
---|
[938] | 341 | class ExportCIF(G2IO.ExportBaseclass): |
---|
[2433] | 342 | '''Base class for CIF exports |
---|
[1068] | 343 | ''' |
---|
[2449] | 344 | def __init__(self,G2frame,formatName,extension,longFormatName=None,): |
---|
| 345 | G2IO.ExportBaseclass.__init__(self,G2frame,formatName,extension,longFormatName=None) |
---|
[2433] | 346 | self.exporttype = [] |
---|
[938] | 347 | self.author = '' |
---|
[2449] | 348 | self.CIFname = '' |
---|
[938] | 349 | |
---|
[2516] | 350 | def ValidateAscii(self,checklist): |
---|
| 351 | '''Validate items as ASCII''' |
---|
| 352 | msg = '' |
---|
| 353 | for lbl,val in checklist: |
---|
| 354 | if not all(ord(c) < 128 for c in val): |
---|
| 355 | if msg: msg += '\n' |
---|
| 356 | msg += lbl + " contains unicode characters: " + val |
---|
| 357 | if msg: |
---|
| 358 | G2G.G2MessageBox(self.G2frame, |
---|
| 359 | 'Error: CIFs can contain only ASCII characters. Please change item(s) below:\n\n'+msg, |
---|
| 360 | 'Unicode not valid for CIF') |
---|
| 361 | return True |
---|
[3011] | 362 | |
---|
[2867] | 363 | def _Exporter(self,event=None,phaseOnly=None,histOnly=None,IncludeOnlyHist=None): |
---|
[2449] | 364 | '''Basic code to export a CIF. Export can be full or simple, as set by |
---|
| 365 | phaseOnly and histOnly which skips distances & angles, etc. |
---|
[2867] | 366 | |
---|
| 367 | phaseOnly: used to export only one phase |
---|
| 368 | histOnly: used to export only one histogram |
---|
| 369 | IncludeOnlyHist: used for a full CIF that includes only one of the |
---|
[3101] | 370 | histograms (from a sequential fit) #TODO: needs lots of work! |
---|
[938] | 371 | ''' |
---|
[1081] | 372 | |
---|
| 373 | #***** define functions for export method ======================================= |
---|
[938] | 374 | def WriteAudit(): |
---|
[1074] | 375 | 'Write the CIF audit values. Perhaps should be in a single element loop.' |
---|
[3011] | 376 | WriteCIFitem(self.fp, '_audit_creation_method', |
---|
[938] | 377 | 'created in GSAS-II') |
---|
[3011] | 378 | WriteCIFitem(self.fp, '_audit_creation_date',self.CIFdate) |
---|
[938] | 379 | if self.author: |
---|
[3011] | 380 | WriteCIFitem(self.fp, '_audit_author_name',self.author) |
---|
| 381 | WriteCIFitem(self.fp, '_audit_update_record', |
---|
[938] | 382 | self.CIFdate+' Initial software-generated CIF') |
---|
| 383 | |
---|
| 384 | def WriteOverall(): |
---|
[963] | 385 | '''Write out overall refinement information. |
---|
| 386 | |
---|
| 387 | More could be done here, but this is a good start. |
---|
[938] | 388 | ''' |
---|
[1658] | 389 | if self.ifPWDR: |
---|
[3011] | 390 | WriteCIFitem(self.fp, '_pd_proc_info_datetime', self.CIFdate) |
---|
| 391 | WriteCIFitem(self.fp, '_pd_calc_method', 'Rietveld Refinement') |
---|
| 392 | #WriteCIFitem(self.fp, '_refine_ls_shift/su_max',DAT1) |
---|
| 393 | #WriteCIFitem(self.fp, '_refine_ls_shift/su_mean',DAT2) |
---|
| 394 | WriteCIFitem(self.fp, '_computing_structure_refinement','GSAS-II (Toby & Von Dreele, J. Appl. Cryst. 46, 544-549, 2013)') |
---|
[1658] | 395 | if self.ifHKLF: |
---|
| 396 | controls = self.OverallParms['Controls'] |
---|
| 397 | if controls['F**2']: |
---|
[3200] | 398 | thresh = 'F**2>%.1fu(F**2)'%(controls['UsrReject']['minF/sig']) |
---|
[1658] | 399 | else: |
---|
[3200] | 400 | thresh = 'F>%.1fu(F)'%(controls['UsrReject']['minF/sig']) |
---|
[3011] | 401 | WriteCIFitem(self.fp, '_reflns_threshold_expression', thresh) |
---|
[956] | 402 | try: |
---|
| 403 | vars = str(len(self.OverallParms['Covariance']['varyList'])) |
---|
| 404 | except: |
---|
| 405 | vars = '?' |
---|
[3011] | 406 | WriteCIFitem(self.fp, '_refine_ls_number_parameters',vars) |
---|
[956] | 407 | try: |
---|
[960] | 408 | GOF = G2mth.ValEsd(self.OverallParms['Covariance']['Rvals']['GOF'],-0.009) |
---|
[956] | 409 | except: |
---|
| 410 | GOF = '?' |
---|
[3011] | 411 | WriteCIFitem(self.fp, '_refine_ls_goodness_of_fit_all',GOF) |
---|
[960] | 412 | |
---|
[963] | 413 | # get restraint info |
---|
| 414 | # restraintDict = self.OverallParms.get('Restraints',{}) |
---|
| 415 | # for i in self.OverallParms['Constraints']: |
---|
| 416 | # print i |
---|
| 417 | # for j in self.OverallParms['Constraints'][i]: |
---|
| 418 | # print j |
---|
[3011] | 419 | #WriteCIFitem(self.fp, '_refine_ls_number_restraints',TEXT) |
---|
[938] | 420 | # other things to consider reporting |
---|
| 421 | # _refine_ls_number_reflns |
---|
| 422 | # _refine_ls_goodness_of_fit_obs |
---|
| 423 | # _refine_ls_wR_factor_obs |
---|
| 424 | # _refine_ls_restrained_S_all |
---|
| 425 | # _refine_ls_restrained_S_obs |
---|
[941] | 426 | |
---|
[938] | 427 | # include an overall profile r-factor, if there is more than one powder histogram |
---|
[1037] | 428 | R = '%.5f'%(self.OverallParms['Covariance']['Rvals']['Rwp']/100.) |
---|
[3011] | 429 | WriteCIFitem(self.fp, '\n# OVERALL WEIGHTED R-FACTOR') |
---|
| 430 | WriteCIFitem(self.fp, '_refine_ls_wR_factor_obs',R) |
---|
[1037] | 431 | # _refine_ls_R_factor_all |
---|
[3011] | 432 | # _refine_ls_R_factor_obs |
---|
| 433 | WriteCIFitem(self.fp, '_refine_ls_matrix_type','full') |
---|
| 434 | #WriteCIFitem(self.fp, '_refine_ls_matrix_type','userblocks') |
---|
[938] | 435 | |
---|
[1074] | 436 | def writeCIFtemplate(G2dict,tmplate,defaultname=''): |
---|
| 437 | '''Write out the selected or edited CIF template |
---|
| 438 | An unedited CIF template file is copied, comments intact; an edited |
---|
[3011] | 439 | CIF template is written out from PyCifRW which of course strips comments. |
---|
[1074] | 440 | In all cases the initial data_ header is stripped (there should only be one!) |
---|
| 441 | ''' |
---|
[1068] | 442 | CIFobj = G2dict.get("CIF_template") |
---|
| 443 | if defaultname: |
---|
| 444 | defaultname = defaultname.encode('ascii','replace').strip().replace(' ','_') |
---|
| 445 | defaultname = re.sub(r'[^a-zA-Z0-9_-]','',defaultname) |
---|
| 446 | defaultname = tmplate + "_" + defaultname + ".cif" |
---|
| 447 | else: |
---|
| 448 | defaultname = '' |
---|
| 449 | templateDefName = 'template_'+tmplate+'.cif' |
---|
| 450 | if not CIFobj: # copying a template |
---|
| 451 | for pth in [os.getcwd()]+sys.path: |
---|
| 452 | fil = os.path.join(pth,defaultname) |
---|
| 453 | if os.path.exists(fil) and defaultname: break |
---|
| 454 | else: |
---|
| 455 | for pth in sys.path: |
---|
| 456 | fil = os.path.join(pth,templateDefName) |
---|
| 457 | if os.path.exists(fil): break |
---|
| 458 | else: |
---|
| 459 | print(CIFobj+' not found in path!') |
---|
| 460 | return |
---|
| 461 | fp = open(fil,'r') |
---|
| 462 | txt = fp.read() |
---|
| 463 | fp.close() |
---|
| 464 | elif type(CIFobj) is not list and type(CIFobj) is not tuple: |
---|
| 465 | if not os.path.exists(CIFobj): |
---|
[1069] | 466 | print("Error: requested template file has disappeared: "+CIFobj) |
---|
[1068] | 467 | return |
---|
| 468 | fp = open(CIFobj,'r') |
---|
| 469 | txt = fp.read() |
---|
| 470 | fp.close() |
---|
| 471 | else: |
---|
| 472 | txt = dict2CIF(CIFobj[0],CIFobj[1]).WriteOut() |
---|
| 473 | # remove the PyCifRW header, if present |
---|
| 474 | #if txt.find('PyCifRW') > -1 and txt.find('data_') > -1: |
---|
| 475 | txt = "# GSAS-II edited template follows "+txt[txt.index("data_")+5:] |
---|
| 476 | #txt = txt.replace('data_','#') |
---|
[3011] | 477 | WriteCIFitem(self.fp, txt) |
---|
[1068] | 478 | |
---|
[960] | 479 | def FormatSH(phasenam): |
---|
[956] | 480 | 'Format a full spherical harmonics texture description as a string' |
---|
[3011] | 481 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
[956] | 482 | pfx = str(phasedict['pId'])+'::' |
---|
| 483 | s = "" |
---|
[3011] | 484 | textureData = phasedict['General']['SH Texture'] |
---|
[956] | 485 | if textureData.get('Order'): |
---|
| 486 | s += "Spherical Harmonics correction. Order = "+str(textureData['Order']) |
---|
| 487 | s += " Model: " + str(textureData['Model']) + "\n Orientation angles: " |
---|
| 488 | for name in ['omega','chi','phi']: |
---|
| 489 | aname = pfx+'SH '+name |
---|
| 490 | s += name + " = " |
---|
| 491 | sig = self.sigDict.get(aname,-0.09) |
---|
| 492 | s += G2mth.ValEsd(self.parmDict[aname],sig) |
---|
| 493 | s += "; " |
---|
| 494 | s += "\n" |
---|
| 495 | s1 = " Coefficients: " |
---|
| 496 | for name in textureData['SH Coeff'][1]: |
---|
| 497 | aname = pfx+name |
---|
| 498 | if len(s1) > 60: |
---|
| 499 | s += s1 + "\n" |
---|
| 500 | s1 = " " |
---|
| 501 | s1 += aname + ' = ' |
---|
| 502 | sig = self.sigDict.get(aname,-0.0009) |
---|
| 503 | s1 += G2mth.ValEsd(self.parmDict[aname],sig) |
---|
| 504 | s1 += "; " |
---|
| 505 | s += s1 |
---|
| 506 | return s |
---|
| 507 | |
---|
[960] | 508 | def FormatHAPpo(phasenam): |
---|
| 509 | '''return the March-Dollase/SH correction for every |
---|
| 510 | histogram in the current phase formatted into a |
---|
| 511 | character string |
---|
| 512 | ''' |
---|
[3011] | 513 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
[956] | 514 | s = '' |
---|
| 515 | for histogram in sorted(phasedict['Histograms']): |
---|
[960] | 516 | if histogram.startswith("HKLF"): continue # powder only |
---|
[956] | 517 | Histogram = self.Histograms.get(histogram) |
---|
| 518 | if not Histogram: continue |
---|
| 519 | hapData = phasedict['Histograms'][histogram] |
---|
| 520 | if hapData['Pref.Ori.'][0] == 'MD': |
---|
| 521 | aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':MD' |
---|
| 522 | if self.parmDict.get(aname,1.0) != 1.0: continue |
---|
| 523 | sig = self.sigDict.get(aname,-0.009) |
---|
| 524 | if s != "": s += '\n' |
---|
| 525 | s += 'March-Dollase correction' |
---|
[1010] | 526 | if len(self.powderDict) > 1: |
---|
[956] | 527 | s += ', histogram '+str(Histogram['hId']+1) |
---|
| 528 | s += ' coef. = ' + G2mth.ValEsd(self.parmDict[aname],sig) |
---|
| 529 | s += ' axis = ' + str(hapData['Pref.Ori.'][3]) |
---|
| 530 | else: # must be SH |
---|
| 531 | if s != "": s += '\n' |
---|
| 532 | s += 'Simple spherical harmonic correction' |
---|
[1010] | 533 | if len(self.powderDict) > 1: |
---|
[956] | 534 | s += ', histogram '+str(Histogram['hId']+1) |
---|
| 535 | s += ' Order = '+str(hapData['Pref.Ori.'][4])+'\n' |
---|
| 536 | s1 = " Coefficients: " |
---|
| 537 | for item in hapData['Pref.Ori.'][5]: |
---|
| 538 | aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':'+item |
---|
| 539 | if len(s1) > 60: |
---|
| 540 | s += s1 + "\n" |
---|
| 541 | s1 = " " |
---|
| 542 | s1 += aname + ' = ' |
---|
| 543 | sig = self.sigDict.get(aname,-0.0009) |
---|
| 544 | s1 += G2mth.ValEsd(self.parmDict[aname],sig) |
---|
| 545 | s1 += "; " |
---|
| 546 | s += s1 |
---|
| 547 | return s |
---|
[3011] | 548 | |
---|
[1013] | 549 | def FormatBackground(bkg,hId): |
---|
[990] | 550 | '''Display the Background information as a descriptive text string. |
---|
[3011] | 551 | |
---|
[990] | 552 | TODO: this needs to be expanded to show the diffuse peak and |
---|
[1022] | 553 | Debye term information as well. (Bob) |
---|
[960] | 554 | |
---|
[990] | 555 | :returns: the text description (str) |
---|
| 556 | ''' |
---|
[1013] | 557 | hfx = ':'+str(hId)+':' |
---|
[990] | 558 | fxn, bkgdict = bkg |
---|
| 559 | terms = fxn[2] |
---|
| 560 | txt = 'Background function: "'+fxn[0]+'" function with '+str(terms)+' terms:\n' |
---|
[1014] | 561 | l = " " |
---|
[1013] | 562 | for i,v in enumerate(fxn[3:]): |
---|
[1496] | 563 | name = '%sBack;%d'%(hfx,i) |
---|
[1013] | 564 | sig = self.sigDict.get(name,-0.009) |
---|
[990] | 565 | if len(l) > 60: |
---|
| 566 | txt += l + '\n' |
---|
[1014] | 567 | l = ' ' |
---|
[1013] | 568 | l += G2mth.ValEsd(v,sig)+', ' |
---|
[990] | 569 | txt += l |
---|
[1014] | 570 | if bkgdict['nDebye']: |
---|
| 571 | txt += '\n Background Debye function parameters: A, R, U:' |
---|
[1496] | 572 | names = ['A;','R;','U;'] |
---|
[1014] | 573 | for i in range(bkgdict['nDebye']): |
---|
| 574 | txt += '\n ' |
---|
| 575 | for j in range(3): |
---|
| 576 | name = hfx+'Debye'+names[j]+str(i) |
---|
| 577 | sig = self.sigDict.get(name,-0.009) |
---|
| 578 | txt += G2mth.ValEsd(bkgdict['debyeTerms'][i][2*j],sig)+', ' |
---|
| 579 | if bkgdict['nPeaks']: |
---|
| 580 | txt += '\n Background peak parameters: pos, int, sig, gam:' |
---|
[1496] | 581 | names = ['pos;','int;','sig;','gam;'] |
---|
[1014] | 582 | for i in range(bkgdict['nPeaks']): |
---|
| 583 | txt += '\n ' |
---|
| 584 | for j in range(4): |
---|
| 585 | name = hfx+'BkPk'+names[j]+str(i) |
---|
| 586 | sig = self.sigDict.get(name,-0.009) |
---|
| 587 | txt += G2mth.ValEsd(bkgdict['peaksList'][i][2*j],sig)+', ' |
---|
[990] | 588 | return txt |
---|
| 589 | |
---|
[1013] | 590 | def FormatInstProfile(instparmdict,hId): |
---|
[960] | 591 | '''Format the instrumental profile parameters with a |
---|
| 592 | string description. Will only be called on PWDR histograms |
---|
| 593 | ''' |
---|
[1012] | 594 | s = '' |
---|
| 595 | inst = instparmdict[0] |
---|
[1013] | 596 | hfx = ':'+str(hId)+':' |
---|
[1012] | 597 | if 'C' in inst['Type'][0]: |
---|
[1013] | 598 | s = 'Finger-Cox-Jephcoat function parameters U, V, W, X, Y, SH/L:\n' |
---|
[1029] | 599 | s += ' peak variance(Gauss) = Utan(Th)^2^+Vtan(Th)+W:\n' |
---|
[1013] | 600 | s += ' peak HW(Lorentz) = X/cos(Th)+Ytan(Th); SH/L = S/L+H/L\n' |
---|
[1029] | 601 | s += ' U, V, W in (centideg)^2^, X & Y in centideg\n ' |
---|
[1012] | 602 | for item in ['U','V','W','X','Y','SH/L']: |
---|
[1013] | 603 | name = hfx+item |
---|
| 604 | sig = self.sigDict.get(name,-0.009) |
---|
[3011] | 605 | s += G2mth.ValEsd(inst[item][1],sig)+', ' |
---|
[1012] | 606 | elif 'T' in inst['Type'][0]: #to be tested after TOF Rietveld done |
---|
| 607 | s = 'Von Dreele-Jorgenson-Windsor function parameters\n'+ \ |
---|
[2354] | 608 | ' alpha, beta-0, beta-1, beta-q, sig-0, sig-1, sig-2, sig-q, X, Y:\n ' |
---|
| 609 | for item in ['alpha','beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','X','Y']: |
---|
[1013] | 610 | name = hfx+item |
---|
| 611 | sig = self.sigDict.get(name,-0.009) |
---|
| 612 | s += G2mth.ValEsd(inst[item][1],sig)+', ' |
---|
[1012] | 613 | return s |
---|
[960] | 614 | |
---|
| 615 | def FormatPhaseProfile(phasenam): |
---|
| 616 | '''Format the phase-related profile parameters (size/strain) |
---|
| 617 | with a string description. |
---|
[1013] | 618 | return an empty string or None if there are no |
---|
[960] | 619 | powder histograms for this phase. |
---|
| 620 | ''' |
---|
| 621 | s = '' |
---|
[1013] | 622 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
[3011] | 623 | SGData = phasedict['General'] ['SGData'] |
---|
[960] | 624 | for histogram in sorted(phasedict['Histograms']): |
---|
| 625 | if histogram.startswith("HKLF"): continue # powder only |
---|
| 626 | Histogram = self.Histograms.get(histogram) |
---|
| 627 | if not Histogram: continue |
---|
| 628 | hapData = phasedict['Histograms'][histogram] |
---|
[1013] | 629 | pId = phasedict['pId'] |
---|
| 630 | hId = Histogram['hId'] |
---|
| 631 | phfx = '%d:%d:'%(pId,hId) |
---|
| 632 | size = hapData['Size'] |
---|
| 633 | mustrain = hapData['Mustrain'] |
---|
| 634 | hstrain = hapData['HStrain'] |
---|
[1130] | 635 | if len(self.powderDict) > 1: |
---|
| 636 | if s: |
---|
| 637 | s += '\n' |
---|
| 638 | else: |
---|
| 639 | s += ' Crystallite size model "%s" for %s (microns)\n '%(size[0],phasenam) |
---|
| 640 | s += ' Parameters for histogram #'+str(hId)+' '+str(histogram)+'\n' |
---|
| 641 | else: |
---|
| 642 | s += ' Crystallite size model "%s" for %s (microns)\n '%(size[0],phasenam) |
---|
[3011] | 643 | |
---|
[1013] | 644 | names = ['Size;i','Size;mx'] |
---|
| 645 | if 'uniax' in size[0]: |
---|
| 646 | names = ['Size;i','Size;a','Size;mx'] |
---|
[1014] | 647 | s += 'anisotropic axis is %s\n '%(str(size[3])) |
---|
| 648 | s += 'parameters: equatorial size, axial size, G/L mix\n ' |
---|
[1013] | 649 | for i,item in enumerate(names): |
---|
| 650 | name = phfx+item |
---|
| 651 | sig = self.sigDict.get(name,-0.009) |
---|
| 652 | s += G2mth.ValEsd(size[1][i],sig)+', ' |
---|
| 653 | elif 'ellip' in size[0]: |
---|
[1014] | 654 | s += 'parameters: S11, S22, S33, S12, S13, S23, G/L mix\n ' |
---|
[1013] | 655 | for i in range(6): |
---|
| 656 | name = phfx+'Size:'+str(i) |
---|
| 657 | sig = self.sigDict.get(name,-0.009) |
---|
| 658 | s += G2mth.ValEsd(size[4][i],sig)+', ' |
---|
| 659 | sig = self.sigDict.get(phfx+'Size;mx',-0.009) |
---|
[3011] | 660 | s += G2mth.ValEsd(size[1][2],sig)+', ' |
---|
[1013] | 661 | else: #isotropic |
---|
[1014] | 662 | s += 'parameters: Size, G/L mix\n ' |
---|
[1013] | 663 | i = 0 |
---|
| 664 | for item in names: |
---|
| 665 | name = phfx+item |
---|
| 666 | sig = self.sigDict.get(name,-0.009) |
---|
| 667 | s += G2mth.ValEsd(size[1][i],sig)+', ' |
---|
[3011] | 668 | i = 2 #skip the aniso value |
---|
[1029] | 669 | s += '\n Mustrain model "%s" for %s (10^6^)\n '%(mustrain[0],phasenam) |
---|
[1013] | 670 | names = ['Mustrain;i','Mustrain;mx'] |
---|
| 671 | if 'uniax' in mustrain[0]: |
---|
| 672 | names = ['Mustrain;i','Mustrain;a','Mustrain;mx'] |
---|
[1014] | 673 | s += 'anisotropic axis is %s\n '%(str(size[3])) |
---|
| 674 | s += 'parameters: equatorial mustrain, axial mustrain, G/L mix\n ' |
---|
[1013] | 675 | for i,item in enumerate(names): |
---|
| 676 | name = phfx+item |
---|
| 677 | sig = self.sigDict.get(name,-0.009) |
---|
| 678 | s += G2mth.ValEsd(mustrain[1][i],sig)+', ' |
---|
| 679 | elif 'general' in mustrain[0]: |
---|
[1014] | 680 | names = 'parameters: ' |
---|
[1013] | 681 | for i,name in enumerate(G2spc.MustrainNames(SGData)): |
---|
| 682 | names += name+', ' |
---|
| 683 | if i == 9: |
---|
| 684 | names += '\n ' |
---|
[1014] | 685 | names += 'G/L mix\n ' |
---|
[1013] | 686 | s += names |
---|
| 687 | txt = '' |
---|
| 688 | for i in range(len(mustrain[4])): |
---|
| 689 | name = phfx+'Mustrain:'+str(i) |
---|
| 690 | sig = self.sigDict.get(name,-0.009) |
---|
| 691 | if len(txt) > 60: |
---|
[1014] | 692 | s += txt+'\n ' |
---|
[1013] | 693 | txt = '' |
---|
| 694 | txt += G2mth.ValEsd(mustrain[4][i],sig)+', ' |
---|
[3011] | 695 | s += txt |
---|
[1013] | 696 | sig = self.sigDict.get(phfx+'Mustrain;mx',-0.009) |
---|
| 697 | s += G2mth.ValEsd(mustrain[1][2],sig)+', ' |
---|
[3011] | 698 | |
---|
[1013] | 699 | else: #isotropic |
---|
[1014] | 700 | s += ' parameters: Mustrain, G/L mix\n ' |
---|
[1013] | 701 | i = 0 |
---|
| 702 | for item in names: |
---|
| 703 | name = phfx+item |
---|
| 704 | sig = self.sigDict.get(name,-0.009) |
---|
| 705 | s += G2mth.ValEsd(mustrain[1][i],sig)+', ' |
---|
[3011] | 706 | i = 2 #skip the aniso value |
---|
[1130] | 707 | s1 = ' \n Macrostrain parameters: ' |
---|
[1013] | 708 | names = G2spc.HStrainNames(SGData) |
---|
| 709 | for name in names: |
---|
[1130] | 710 | s1 += name+', ' |
---|
| 711 | s1 += '\n ' |
---|
| 712 | macrostrain = False |
---|
[1013] | 713 | for i in range(len(names)): |
---|
| 714 | name = phfx+name[i] |
---|
| 715 | sig = self.sigDict.get(name,-0.009) |
---|
[1130] | 716 | s1 += G2mth.ValEsd(hstrain[0][i],sig)+', ' |
---|
| 717 | if hstrain[0][i]: macrostrain = True |
---|
| 718 | if macrostrain: |
---|
| 719 | s += s1 + '\n' |
---|
| 720 | # show revised lattice parameters here someday |
---|
| 721 | else: |
---|
| 722 | s += '\n' |
---|
[1013] | 723 | return s |
---|
[956] | 724 | |
---|
| 725 | def MakeUniqueLabel(lbl,labellist): |
---|
| 726 | 'Make sure that every atom label is unique' |
---|
| 727 | lbl = lbl.strip() |
---|
| 728 | if not lbl: # deal with a blank label |
---|
| 729 | lbl = 'A_1' |
---|
| 730 | if lbl not in labellist: |
---|
| 731 | labellist.append(lbl) |
---|
| 732 | return lbl |
---|
| 733 | i = 1 |
---|
| 734 | prefix = lbl |
---|
| 735 | if '_' in lbl: |
---|
| 736 | prefix = lbl[:lbl.rfind('_')] |
---|
| 737 | suffix = lbl[lbl.rfind('_')+1:] |
---|
| 738 | try: |
---|
| 739 | i = int(suffix)+1 |
---|
| 740 | except: |
---|
| 741 | pass |
---|
| 742 | while prefix+'_'+str(i) in labellist: |
---|
| 743 | i += 1 |
---|
| 744 | else: |
---|
| 745 | lbl = prefix+'_'+str(i) |
---|
| 746 | labellist.append(lbl) |
---|
| 747 | |
---|
[3011] | 748 | # Factored out to above by Jack O'Donnell, so it |
---|
| 749 | # could be accessed by GSASIIscriptable.py |
---|
| 750 | # def WriteAtomsNuclear(phasenam): |
---|
| 751 | # 'Write atom positions to CIF' |
---|
| 752 | # phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
| 753 | # General = phasedict['General'] |
---|
| 754 | # cx,ct,cs,cia = General['AtomPtrs'] |
---|
| 755 | # Atoms = phasedict['Atoms'] |
---|
| 756 | # cfrac = cx+3 |
---|
| 757 | # fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
| 758 | # for i,at in enumerate(Atoms): |
---|
| 759 | # fval = self.parmDict.get(fpfx+str(i),at[cfrac]) |
---|
| 760 | # if fval != 0.0: |
---|
| 761 | # break |
---|
| 762 | # else: |
---|
| 763 | # WriteCIFitem(self.fp, '\n# PHASE HAS NO ATOMS!') |
---|
| 764 | # return |
---|
[956] | 765 | |
---|
[3011] | 766 | # WriteCIFitem(self.fp, '\n# ATOMIC COORDINATES AND DISPLACEMENT PARAMETERS') |
---|
| 767 | # WriteCIFitem(self.fp, 'loop_ '+ |
---|
| 768 | # '\n _atom_site_label'+ |
---|
| 769 | # '\n _atom_site_type_symbol'+ |
---|
| 770 | # '\n _atom_site_fract_x'+ |
---|
| 771 | # '\n _atom_site_fract_y'+ |
---|
| 772 | # '\n _atom_site_fract_z'+ |
---|
| 773 | # '\n _atom_site_occupancy'+ |
---|
| 774 | # '\n _atom_site_adp_type'+ |
---|
| 775 | # '\n _atom_site_U_iso_or_equiv'+ |
---|
| 776 | # '\n _atom_site_symmetry_multiplicity') |
---|
[960] | 777 | |
---|
[3011] | 778 | # varnames = {cx:'Ax',cx+1:'Ay',cx+2:'Az',cx+3:'Afrac', |
---|
| 779 | # cia+1:'AUiso',cia+2:'AU11',cia+3:'AU22',cia+4:'AU33', |
---|
| 780 | # cia+5:'AU12',cia+6:'AU13',cia+7:'AU23'} |
---|
| 781 | # self.labellist = [] |
---|
| 782 | |
---|
| 783 | # pfx = str(phasedict['pId'])+'::' |
---|
| 784 | # # loop over all atoms |
---|
| 785 | # naniso = 0 |
---|
| 786 | # for i,at in enumerate(Atoms): |
---|
| 787 | # if phasedict['General']['Type'] == 'macromolecular': |
---|
| 788 | # label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2]) |
---|
| 789 | # s = PutInCol(MakeUniqueLabel(label,self.labellist),15) # label |
---|
| 790 | # else: |
---|
| 791 | # s = PutInCol(MakeUniqueLabel(at[ct-1],self.labellist),6) # label |
---|
| 792 | # fval = self.parmDict.get(fpfx+str(i),at[cfrac]) |
---|
| 793 | # if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact) |
---|
| 794 | # s += PutInCol(FmtAtomType(at[ct]),4) # type |
---|
| 795 | # if at[cia] == 'I': |
---|
| 796 | # adp = 'Uiso ' |
---|
| 797 | # else: |
---|
| 798 | # adp = 'Uani ' |
---|
| 799 | # naniso += 1 |
---|
| 800 | # # compute Uequiv crudely |
---|
| 801 | # # correct: Defined as "1/3 trace of diagonalized U matrix". |
---|
| 802 | # # SEE cell2GS & Uij2Ueqv to GSASIIlattice. Former is needed to make the GS matrix used by the latter. |
---|
| 803 | # t = 0.0 |
---|
| 804 | # for j in (2,3,4): |
---|
| 805 | # var = pfx+varnames[cia+j]+":"+str(i) |
---|
| 806 | # t += self.parmDict.get(var,at[cia+j]) |
---|
| 807 | # for j in (cx,cx+1,cx+2,cx+3,cia,cia+1): |
---|
| 808 | # if j in (cx,cx+1,cx+2): |
---|
| 809 | # dig = 11 |
---|
| 810 | # sigdig = -0.00009 |
---|
| 811 | # else: |
---|
| 812 | # dig = 10 |
---|
| 813 | # sigdig = -0.009 |
---|
| 814 | # if j == cia: |
---|
| 815 | # s += adp |
---|
| 816 | # else: |
---|
| 817 | # var = pfx+varnames[j]+":"+str(i) |
---|
| 818 | # dvar = pfx+"d"+varnames[j]+":"+str(i) |
---|
| 819 | # if dvar not in self.sigDict: |
---|
| 820 | # dvar = var |
---|
| 821 | # if j == cia+1 and adp == 'Uani ': |
---|
| 822 | # val = t/3. |
---|
| 823 | # sig = sigdig |
---|
| 824 | # else: |
---|
| 825 | # #print var,(var in self.parmDict),(var in self.sigDict) |
---|
| 826 | # val = self.parmDict.get(var,at[j]) |
---|
| 827 | # sig = self.sigDict.get(dvar,sigdig) |
---|
| 828 | # s += PutInCol(G2mth.ValEsd(val,sig),dig) |
---|
| 829 | # s += PutInCol(at[cs+1],3) |
---|
| 830 | # WriteCIFitem(self.fp, s) |
---|
| 831 | # if naniso == 0: return |
---|
| 832 | # # now loop over aniso atoms |
---|
| 833 | # WriteCIFitem(self.fp, '\nloop_' + '\n _atom_site_aniso_label' + |
---|
| 834 | # '\n _atom_site_aniso_U_11' + '\n _atom_site_aniso_U_22' + |
---|
| 835 | # '\n _atom_site_aniso_U_33' + '\n _atom_site_aniso_U_12' + |
---|
| 836 | # '\n _atom_site_aniso_U_13' + '\n _atom_site_aniso_U_23') |
---|
| 837 | # for i,at in enumerate(Atoms): |
---|
| 838 | # fval = self.parmDict.get(fpfx+str(i),at[cfrac]) |
---|
| 839 | # if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact) |
---|
| 840 | # if at[cia] == 'I': continue |
---|
| 841 | # s = PutInCol(self.labellist[i],6) # label |
---|
| 842 | # for j in (2,3,4,5,6,7): |
---|
| 843 | # sigdig = -0.0009 |
---|
| 844 | # var = pfx+varnames[cia+j]+":"+str(i) |
---|
| 845 | # val = self.parmDict.get(var,at[cia+j]) |
---|
| 846 | # sig = self.sigDict.get(var,sigdig) |
---|
| 847 | # s += PutInCol(G2mth.ValEsd(val,sig),11) |
---|
| 848 | # WriteCIFitem(self.fp, s) |
---|
| 849 | |
---|
[3019] | 850 | # def HillSortElements(elmlist): |
---|
| 851 | # '''Sort elements in "Hill" order: C, H, others, (where others |
---|
| 852 | # are alphabetical). |
---|
[960] | 853 | |
---|
[3019] | 854 | # :params list elmlist: a list of element strings |
---|
[960] | 855 | |
---|
[3019] | 856 | # :returns: a sorted list of element strings |
---|
| 857 | # ''' |
---|
| 858 | # newlist = [] |
---|
| 859 | # oldlist = elmlist[:] |
---|
| 860 | # for elm in ('C','H'): |
---|
| 861 | # if elm in elmlist: |
---|
| 862 | # newlist.append(elm) |
---|
| 863 | # oldlist.pop(oldlist.index(elm)) |
---|
| 864 | # return newlist+sorted(oldlist) |
---|
[960] | 865 | |
---|
[3011] | 866 | # Factored out to above by Jackson O'Donnell |
---|
| 867 | # so that it can be accessed by GSASIIscriptable |
---|
[960] | 868 | |
---|
[3011] | 869 | # def WriteComposition(phasenam): |
---|
| 870 | # '''determine the composition for the unit cell, crudely determine Z and |
---|
| 871 | # then compute the composition in formula units |
---|
| 872 | # ''' |
---|
| 873 | # phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
| 874 | # General = phasedict['General'] |
---|
| 875 | # Z = General.get('cellZ',0.0) |
---|
| 876 | # cx,ct,cs,cia = General['AtomPtrs'] |
---|
| 877 | # Atoms = phasedict['Atoms'] |
---|
| 878 | # fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
| 879 | # cfrac = cx+3 |
---|
| 880 | # cmult = cs+1 |
---|
| 881 | # compDict = {} # combines H,D & T |
---|
| 882 | # sitemultlist = [] |
---|
| 883 | # massDict = dict(zip(General['AtomTypes'],General['AtomMass'])) |
---|
| 884 | # cellmass = 0 |
---|
| 885 | # for i,at in enumerate(Atoms): |
---|
| 886 | # atype = at[ct].strip() |
---|
| 887 | # if atype.find('-') != -1: atype = atype.split('-')[0] |
---|
| 888 | # if atype.find('+') != -1: atype = atype.split('+')[0] |
---|
| 889 | # atype = atype[0].upper()+atype[1:2].lower() # force case conversion |
---|
| 890 | # if atype == "D" or atype == "D": atype = "H" |
---|
| 891 | # fvar = fpfx+str(i) |
---|
| 892 | # fval = self.parmDict.get(fvar,at[cfrac]) |
---|
| 893 | # mult = at[cmult] |
---|
| 894 | # if not massDict.get(at[ct]): |
---|
| 895 | # print('Error: No mass found for atom type '+at[ct]) |
---|
| 896 | # print('Will not compute cell contents for phase '+phasenam) |
---|
| 897 | # return |
---|
| 898 | # cellmass += massDict[at[ct]]*mult*fval |
---|
| 899 | # compDict[atype] = compDict.get(atype,0.0) + mult*fval |
---|
| 900 | # if fval == 1: sitemultlist.append(mult) |
---|
| 901 | # if len(compDict.keys()) == 0: return # no elements! |
---|
| 902 | # if Z < 1: # Z has not been computed or set by user |
---|
| 903 | # Z = 1 |
---|
| 904 | # if not sitemultlist: |
---|
| 905 | # General['cellZ'] = 1 |
---|
| 906 | # return |
---|
| 907 | # for i in range(2,min(sitemultlist)+1): |
---|
| 908 | # for m in sitemultlist: |
---|
| 909 | # if m % i != 0: |
---|
| 910 | # break |
---|
| 911 | # else: |
---|
| 912 | # Z = i |
---|
| 913 | # General['cellZ'] = Z # save it |
---|
| 914 | |
---|
| 915 | # # when scattering factors are included in the CIF, this needs to be |
---|
| 916 | # # added to the loop here but only in the one-block case. |
---|
| 917 | # # For multiblock CIFs, scattering factors go in the histogram |
---|
| 918 | # # blocks (for all atoms in all appropriate phases) - an example?: |
---|
[1044] | 919 | #loop_ |
---|
[3011] | 920 | # _at# om_type_symbol |
---|
| 921 | # _at# om_type_description |
---|
| 922 | # _at# om_type_scat_dispersion_real |
---|
| 923 | # _at# om_type_scat_dispersion_imag |
---|
| 924 | # _at# om_type_scat_source |
---|
| 925 | # 'C'# 'C' 0.0033 0.0016 |
---|
| 926 | # # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 927 | # 'H'# 'H' 0.0000 0.0000 |
---|
| 928 | # # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 929 | # 'P'# 'P' 0.1023 0.0942 |
---|
| 930 | # # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 931 | # 'Cl# ' 'Cl' 0.1484 0.1585 |
---|
| 932 | # # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
| 933 | # 'Cu# ' 'Cu' 0.3201 1.2651 |
---|
| 934 | # # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' |
---|
[960] | 935 | |
---|
[3011] | 936 | # #if oneblock: # add scattering factors for current phase here |
---|
| 937 | # WriteCIFitem(self.fp, '\nloop_ _atom_type_symbol _atom_type_number_in_cell') |
---|
| 938 | # formula = '' |
---|
| 939 | # reload(G2mth) |
---|
| 940 | # for elem in HillSortElements(compDict.keys()): |
---|
| 941 | # WriteCIFitem(self.fp, ' ' + PutInCol(elem,4) + |
---|
| 942 | # G2mth.ValEsd(compDict[elem],-0.009,True)) |
---|
| 943 | # if formula: formula += " " |
---|
| 944 | # formula += elem |
---|
| 945 | # if compDict[elem] == Z: continue |
---|
| 946 | # formula += G2mth.ValEsd(compDict[elem]/Z,-0.009,True) |
---|
| 947 | # WriteCIFitem(self.fp, '\n# Note that Z affects _cell_formula_sum and _weight') |
---|
| 948 | # WriteCIFitem(self.fp, '_cell_formula_units_Z',str(Z)) |
---|
| 949 | # WriteCIFitem(self.fp, '_chemical_formula_sum',formula) |
---|
| 950 | # WriteCIFitem(self.fp, '_chemical_formula_weight', |
---|
| 951 | # G2mth.ValEsd(cellmass/Z,-0.09,True)) |
---|
[960] | 952 | |
---|
[963] | 953 | def WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList): |
---|
| 954 | '''Report bond distances and angles for the CIF |
---|
| 955 | |
---|
| 956 | Note that _geom_*_symmetry_* fields are values of form |
---|
| 957 | n_klm where n is the symmetry operation in SymOpList (counted |
---|
| 958 | starting with 1) and (k-5, l-5, m-5) are translations to add |
---|
| 959 | to (x,y,z). See |
---|
| 960 | http://www.iucr.org/__data/iucr/cifdic_html/1/cif_core.dic/Igeom_angle_site_symmetry_.html |
---|
| 961 | |
---|
| 962 | TODO: need a method to select publication flags for distances/angles |
---|
| 963 | ''' |
---|
[3011] | 964 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
[963] | 965 | Atoms = phasedict['Atoms'] |
---|
[1022] | 966 | generalData = phasedict['General'] |
---|
[1077] | 967 | # create a dict for storing Pub flag for bonds/angles, if needed |
---|
| 968 | if phasedict['General'].get("DisAglHideFlag") is None: |
---|
| 969 | phasedict['General']["DisAglHideFlag"] = {} |
---|
| 970 | DisAngSel = phasedict['General']["DisAglHideFlag"] |
---|
[963] | 971 | cx,ct,cs,cia = phasedict['General']['AtomPtrs'] |
---|
[1022] | 972 | cn = ct-1 |
---|
[3011] | 973 | fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
[963] | 974 | cfrac = cx+3 |
---|
[1022] | 975 | DisAglData = {} |
---|
[1026] | 976 | # create a list of atoms, but skip atoms with zero occupancy |
---|
[1022] | 977 | xyz = [] |
---|
[3011] | 978 | fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
[1022] | 979 | for i,atom in enumerate(Atoms): |
---|
[1026] | 980 | if self.parmDict.get(fpfx+str(i),atom[cfrac]) == 0.0: continue |
---|
[1022] | 981 | xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3]) |
---|
[1126] | 982 | if 'DisAglCtls' not in generalData: |
---|
| 983 | # should not happen, since DisAglDialog should be called |
---|
| 984 | # for all phases before getting here |
---|
[3000] | 985 | dlg = G2G.DisAglDialog( |
---|
[1126] | 986 | self.G2frame, |
---|
| 987 | {}, |
---|
| 988 | generalData) |
---|
[1022] | 989 | if dlg.ShowModal() == wx.ID_OK: |
---|
[1126] | 990 | generalData['DisAglCtls'] = dlg.GetData() |
---|
[1022] | 991 | else: |
---|
| 992 | dlg.Destroy() |
---|
| 993 | return |
---|
| 994 | dlg.Destroy() |
---|
| 995 | DisAglData['OrigAtoms'] = xyz |
---|
| 996 | DisAglData['TargAtoms'] = xyz |
---|
[2567] | 997 | SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps( |
---|
[1022] | 998 | generalData['SGData']) |
---|
| 999 | |
---|
[2567] | 1000 | # xpandSGdata = generalData['SGData'].copy() |
---|
| 1001 | # xpandSGdata.update({'SGOps':symOpList, |
---|
| 1002 | # 'SGInv':False, |
---|
| 1003 | # 'SGLatt':'P', |
---|
| 1004 | # 'SGCen':np.array([[0, 0, 0]]),}) |
---|
| 1005 | # DisAglData['SGData'] = xpandSGdata |
---|
| 1006 | DisAglData['SGData'] = generalData['SGData'].copy() |
---|
[1022] | 1007 | |
---|
| 1008 | DisAglData['Cell'] = generalData['Cell'][1:] #+ volume |
---|
| 1009 | if 'pId' in phasedict: |
---|
| 1010 | DisAglData['pId'] = phasedict['pId'] |
---|
| 1011 | DisAglData['covData'] = self.OverallParms['Covariance'] |
---|
| 1012 | try: |
---|
[1126] | 1013 | AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle( |
---|
| 1014 | generalData['DisAglCtls'], |
---|
| 1015 | DisAglData) |
---|
[1022] | 1016 | except KeyError: # inside DistAngle for missing atom types in DisAglCtls |
---|
[3024] | 1017 | print(u'**** ERROR computing distances & angles for phase {} ****\nresetting to default values'.format(phasenam)) |
---|
| 1018 | data = generalData['DisAglCtls'] = {} |
---|
| 1019 | data['Name'] = generalData['Name'] |
---|
| 1020 | data['Factors'] = [0.85,0.85] |
---|
| 1021 | data['AtomTypes'] = generalData['AtomTypes'] |
---|
| 1022 | data['BondRadii'] = generalData['BondRadii'][:] |
---|
| 1023 | data['AngleRadii'] = generalData['AngleRadii'][:] |
---|
| 1024 | try: |
---|
| 1025 | AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle( |
---|
| 1026 | generalData['DisAglCtls'], |
---|
| 1027 | DisAglData) |
---|
| 1028 | except: |
---|
| 1029 | print('Reset failed. To fix this, use the Reset button in the "edit distance/angle menu" for this phase') |
---|
| 1030 | return |
---|
[3011] | 1031 | |
---|
[963] | 1032 | # loop over interatomic distances for this phase |
---|
[3011] | 1033 | WriteCIFitem(self.fp, '\n# MOLECULAR GEOMETRY') |
---|
| 1034 | WriteCIFitem(self.fp, 'loop_' + |
---|
[1117] | 1035 | '\n _geom_bond_atom_site_label_1' + |
---|
[3011] | 1036 | '\n _geom_bond_atom_site_label_2' + |
---|
| 1037 | '\n _geom_bond_distance' + |
---|
| 1038 | '\n _geom_bond_site_symmetry_1' + |
---|
| 1039 | '\n _geom_bond_site_symmetry_2' + |
---|
[1117] | 1040 | '\n _geom_bond_publ_flag') |
---|
[963] | 1041 | |
---|
[1026] | 1042 | for i in sorted(AtomLabels.keys()): |
---|
| 1043 | Dist = DistArray[i] |
---|
| 1044 | for D in Dist: |
---|
| 1045 | line = ' '+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[D[0]],6) |
---|
| 1046 | sig = D[4] |
---|
| 1047 | if sig == 0: sig = -0.00009 |
---|
| 1048 | line += PutInCol(G2mth.ValEsd(D[3],sig,True),10) |
---|
| 1049 | line += " 1_555 " |
---|
[2567] | 1050 | line += " {:3d}_".format(G2opcodes.index(D[2])+1) |
---|
[1026] | 1051 | for d in D[1]: |
---|
| 1052 | line += "{:1d}".format(d+5) |
---|
[1077] | 1053 | if DisAngSel.get((i,tuple(D[0:3]))): |
---|
| 1054 | line += " no" |
---|
| 1055 | else: |
---|
| 1056 | line += " yes" |
---|
[3011] | 1057 | WriteCIFitem(self.fp, line) |
---|
[963] | 1058 | |
---|
| 1059 | # loop over interatomic angles for this phase |
---|
[3011] | 1060 | WriteCIFitem(self.fp, '\nloop_' + |
---|
| 1061 | '\n _geom_angle_atom_site_label_1' + |
---|
| 1062 | '\n _geom_angle_atom_site_label_2' + |
---|
| 1063 | '\n _geom_angle_atom_site_label_3' + |
---|
| 1064 | '\n _geom_angle' + |
---|
[1117] | 1065 | '\n _geom_angle_site_symmetry_1' + |
---|
[3011] | 1066 | '\n _geom_angle_site_symmetry_2' + |
---|
| 1067 | '\n _geom_angle_site_symmetry_3' + |
---|
[1117] | 1068 | '\n _geom_angle_publ_flag') |
---|
[963] | 1069 | |
---|
[1026] | 1070 | for i in sorted(AtomLabels.keys()): |
---|
| 1071 | Dist = DistArray[i] |
---|
| 1072 | for k,j,tup in AngArray[i]: |
---|
| 1073 | Dj = Dist[j] |
---|
| 1074 | Dk = Dist[k] |
---|
| 1075 | line = ' '+PutInCol(AtomLabels[Dj[0]],6)+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[Dk[0]],6) |
---|
| 1076 | sig = tup[1] |
---|
| 1077 | if sig == 0: sig = -0.009 |
---|
| 1078 | line += PutInCol(G2mth.ValEsd(tup[0],sig,True),10) |
---|
[2567] | 1079 | line += " {:3d}_".format(G2opcodes.index(Dj[2])+1) |
---|
[1026] | 1080 | for d in Dj[1]: |
---|
| 1081 | line += "{:1d}".format(d+5) |
---|
| 1082 | line += " 1_555 " |
---|
[2567] | 1083 | line += " {:3d}_".format(G2opcodes.index(Dk[2])+1) |
---|
[1026] | 1084 | for d in Dk[1]: |
---|
| 1085 | line += "{:1d}".format(d+5) |
---|
[1077] | 1086 | key = (tuple(Dk[0:3]),i,tuple(Dj[0:3])) |
---|
| 1087 | if DisAngSel.get(key): |
---|
| 1088 | line += " no" |
---|
| 1089 | else: |
---|
| 1090 | line += " yes" |
---|
[3011] | 1091 | WriteCIFitem(self.fp, line) |
---|
[963] | 1092 | |
---|
[2433] | 1093 | def WritePhaseInfo(phasenam,hist=None): |
---|
[1074] | 1094 | 'Write out the phase information for the selected phase' |
---|
[3011] | 1095 | WriteCIFitem(self.fp, '\n# phase info for '+str(phasenam) + ' follows') |
---|
| 1096 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
| 1097 | WriteCIFitem(self.fp, '_pd_phase_name', phasenam) |
---|
[1117] | 1098 | cellList,cellSig = self.GetCell(phasenam) |
---|
[956] | 1099 | defsigL = 3*[-0.00001] + 3*[-0.001] + [-0.01] # significance to use when no sigma |
---|
| 1100 | names = ['length_a','length_b','length_c', |
---|
| 1101 | 'angle_alpha','angle_beta ','angle_gamma', |
---|
| 1102 | 'volume'] |
---|
| 1103 | prevsig = 0 |
---|
| 1104 | for lbl,defsig,val,sig in zip(names,defsigL,cellList,cellSig): |
---|
| 1105 | if sig: |
---|
| 1106 | txt = G2mth.ValEsd(val,sig) |
---|
| 1107 | prevsig = -sig # use this as the significance for next value |
---|
| 1108 | else: |
---|
| 1109 | txt = G2mth.ValEsd(val,min(defsig,prevsig),True) |
---|
[3011] | 1110 | WriteCIFitem(self.fp, '_cell_'+lbl,txt) |
---|
| 1111 | |
---|
| 1112 | WriteCIFitem(self.fp, '_symmetry_cell_setting', |
---|
[941] | 1113 | phasedict['General']['SGData']['SGSys']) |
---|
| 1114 | |
---|
| 1115 | spacegroup = phasedict['General']['SGData']['SpGrp'].strip() |
---|
| 1116 | # regularize capitalization and remove trailing H/R |
---|
| 1117 | spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ') |
---|
[3011] | 1118 | WriteCIFitem(self.fp, '_symmetry_space_group_name_H-M',spacegroup) |
---|
[956] | 1119 | |
---|
[941] | 1120 | # generate symmetry operations including centering and center of symmetry |
---|
[2567] | 1121 | SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps( |
---|
[963] | 1122 | phasedict['General']['SGData']) |
---|
[3011] | 1123 | WriteCIFitem(self.fp, 'loop_\n _space_group_symop_id\n _space_group_symop_operation_xyz') |
---|
[963] | 1124 | for i,op in enumerate(SymOpList,start=1): |
---|
[3011] | 1125 | WriteCIFitem(self.fp, ' {:3d} {:}'.format(i,op.lower())) |
---|
[941] | 1126 | |
---|
| 1127 | # loop over histogram(s) used in this phase |
---|
[2433] | 1128 | if not oneblock and not self.quickmode and not hist: |
---|
[960] | 1129 | # report pointers to the histograms used in this phase |
---|
[941] | 1130 | histlist = [] |
---|
[956] | 1131 | for hist in self.Phases[phasenam]['Histograms']: |
---|
| 1132 | if self.Phases[phasenam]['Histograms'][hist]['Use']: |
---|
[941] | 1133 | if phasebyhistDict.get(hist): |
---|
| 1134 | phasebyhistDict[hist].append(phasenam) |
---|
| 1135 | else: |
---|
| 1136 | phasebyhistDict[hist] = [phasenam,] |
---|
| 1137 | blockid = datablockidDict.get(hist) |
---|
| 1138 | if not blockid: |
---|
[1068] | 1139 | print("Internal error: no block for data. Phase "+str( |
---|
| 1140 | phasenam)+" histogram "+str(hist)) |
---|
[941] | 1141 | histlist = [] |
---|
| 1142 | break |
---|
| 1143 | histlist.append(blockid) |
---|
| 1144 | |
---|
| 1145 | if len(histlist) == 0: |
---|
[3011] | 1146 | WriteCIFitem(self.fp, '# Note: phase has no associated data') |
---|
[956] | 1147 | |
---|
[960] | 1148 | # report atom params |
---|
[1079] | 1149 | if phasedict['General']['Type'] in ['nuclear','macromolecular']: #this needs macromolecular variant, etc! |
---|
[3011] | 1150 | try: |
---|
| 1151 | self.labellist |
---|
| 1152 | except AttributeError: |
---|
| 1153 | self.labellist = [] |
---|
| 1154 | WriteAtomsNuclear(self.fp, self.Phases[phasenam], phasenam, |
---|
| 1155 | self.parmDict, self.sigDict, self.labellist) |
---|
[956] | 1156 | else: |
---|
[3136] | 1157 | raise Exception("no export for "+str(phasedict['General']['Type'])+" coordinates implemented") |
---|
[960] | 1158 | # report cell contents |
---|
[3011] | 1159 | WriteComposition(self.fp, self.Phases[phasenam], phasenam, self.parmDict) |
---|
[1079] | 1160 | if not self.quickmode and phasedict['General']['Type'] == 'nuclear': # report distances and angles |
---|
[963] | 1161 | WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList) |
---|
[1659] | 1162 | if 'Map' in phasedict['General'] and 'minmax' in phasedict['General']['Map']: |
---|
[3011] | 1163 | WriteCIFitem(self.fp, '\n# Difference density results') |
---|
[1659] | 1164 | MinMax = phasedict['General']['Map']['minmax'] |
---|
[3011] | 1165 | WriteCIFitem(self.fp, '_refine_diff_density_max',G2mth.ValEsd(MinMax[0],-0.009)) |
---|
| 1166 | WriteCIFitem(self.fp, '_refine_diff_density_min',G2mth.ValEsd(MinMax[1],-0.009)) |
---|
| 1167 | |
---|
[1022] | 1168 | def Yfmt(ndec,val): |
---|
| 1169 | 'Format intensity values' |
---|
| 1170 | out = ("{:."+str(ndec)+"f}").format(val) |
---|
| 1171 | out = out.rstrip('0') # strip zeros to right of decimal |
---|
| 1172 | return out.rstrip('.') # and decimal place when not needed |
---|
[3011] | 1173 | |
---|
[1030] | 1174 | def WriteReflStat(refcount,hklmin,hklmax,dmin,dmax,nRefSets=1): |
---|
[1074] | 1175 | 'Write reflection statistics' |
---|
[3011] | 1176 | WriteCIFitem(self.fp, '_reflns_number_total', str(refcount)) |
---|
[1030] | 1177 | if hklmin is not None and nRefSets == 1: # hkl range has no meaning with multiple phases |
---|
[3011] | 1178 | WriteCIFitem(self.fp, '_reflns_limit_h_min', str(int(hklmin[0]))) |
---|
| 1179 | WriteCIFitem(self.fp, '_reflns_limit_h_max', str(int(hklmax[0]))) |
---|
| 1180 | WriteCIFitem(self.fp, '_reflns_limit_k_min', str(int(hklmin[1]))) |
---|
| 1181 | WriteCIFitem(self.fp, '_reflns_limit_k_max', str(int(hklmax[1]))) |
---|
| 1182 | WriteCIFitem(self.fp, '_reflns_limit_l_min', str(int(hklmin[2]))) |
---|
| 1183 | WriteCIFitem(self.fp, '_reflns_limit_l_max', str(int(hklmax[2]))) |
---|
[1030] | 1184 | if hklmin is not None: |
---|
[3011] | 1185 | WriteCIFitem(self.fp, '_reflns_d_resolution_low ', G2mth.ValEsd(dmax,-0.009)) |
---|
| 1186 | WriteCIFitem(self.fp, '_reflns_d_resolution_high ', G2mth.ValEsd(dmin,-0.009)) |
---|
[941] | 1187 | |
---|
[938] | 1188 | def WritePowderData(histlbl): |
---|
[1074] | 1189 | 'Write out the selected powder diffraction histogram info' |
---|
[956] | 1190 | histblk = self.Histograms[histlbl] |
---|
[981] | 1191 | inst = histblk['Instrument Parameters'][0] |
---|
| 1192 | hId = histblk['hId'] |
---|
| 1193 | pfx = ':' + str(hId) + ':' |
---|
[3011] | 1194 | |
---|
[981] | 1195 | if 'Lam1' in inst: |
---|
| 1196 | ratio = self.parmDict.get('I(L2)/I(L1)',inst['I(L2)/I(L1)'][1]) |
---|
| 1197 | sratio = self.sigDict.get('I(L2)/I(L1)',-0.0009) |
---|
| 1198 | lam1 = self.parmDict.get('Lam1',inst['Lam1'][1]) |
---|
| 1199 | slam1 = self.sigDict.get('Lam1',-0.00009) |
---|
| 1200 | lam2 = self.parmDict.get('Lam2',inst['Lam2'][1]) |
---|
| 1201 | slam2 = self.sigDict.get('Lam2',-0.00009) |
---|
| 1202 | # always assume Ka1 & Ka2 if two wavelengths are present |
---|
[3011] | 1203 | WriteCIFitem(self.fp, '_diffrn_radiation_type','K\\a~1,2~') |
---|
| 1204 | WriteCIFitem(self.fp, 'loop_' + |
---|
[1117] | 1205 | '\n _diffrn_radiation_wavelength' + |
---|
[3011] | 1206 | '\n _diffrn_radiation_wavelength_wt' + |
---|
[1117] | 1207 | '\n _diffrn_radiation_wavelength_id') |
---|
[3011] | 1208 | WriteCIFitem(self.fp, ' ' + PutInCol(G2mth.ValEsd(lam1,slam1),15)+ |
---|
| 1209 | PutInCol('1.0',15) + |
---|
[981] | 1210 | PutInCol('1',5)) |
---|
[3011] | 1211 | WriteCIFitem(self.fp, ' ' + PutInCol(G2mth.ValEsd(lam2,slam2),15)+ |
---|
[981] | 1212 | PutInCol(G2mth.ValEsd(ratio,sratio),15)+ |
---|
[3011] | 1213 | PutInCol('2',5)) |
---|
[2354] | 1214 | elif 'Lam' in inst: |
---|
[1010] | 1215 | lam1 = self.parmDict.get('Lam',inst['Lam'][1]) |
---|
[981] | 1216 | slam1 = self.sigDict.get('Lam',-0.00009) |
---|
[3011] | 1217 | WriteCIFitem(self.fp, '_diffrn_radiation_wavelength',G2mth.ValEsd(lam1,slam1)) |
---|
[981] | 1218 | |
---|
[941] | 1219 | if not oneblock: |
---|
| 1220 | if not phasebyhistDict.get(histlbl): |
---|
[3011] | 1221 | WriteCIFitem(self.fp, '\n# No phases associated with this data set') |
---|
[941] | 1222 | else: |
---|
[3011] | 1223 | WriteCIFitem(self.fp, '\n# PHASE TABLE') |
---|
| 1224 | WriteCIFitem(self.fp, 'loop_' + |
---|
| 1225 | '\n _pd_phase_id' + |
---|
| 1226 | '\n _pd_phase_block_id' + |
---|
[1117] | 1227 | '\n _pd_phase_mass_%') |
---|
[989] | 1228 | wtFrSum = 0. |
---|
[941] | 1229 | for phasenam in phasebyhistDict.get(histlbl): |
---|
[989] | 1230 | hapData = self.Phases[phasenam]['Histograms'][histlbl] |
---|
| 1231 | General = self.Phases[phasenam]['General'] |
---|
| 1232 | wtFrSum += hapData['Scale'][0]*General['Mass'] |
---|
[941] | 1233 | |
---|
[989] | 1234 | for phasenam in phasebyhistDict.get(histlbl): |
---|
| 1235 | hapData = self.Phases[phasenam]['Histograms'][histlbl] |
---|
| 1236 | General = self.Phases[phasenam]['General'] |
---|
| 1237 | wtFr = hapData['Scale'][0]*General['Mass']/wtFrSum |
---|
| 1238 | pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':' |
---|
| 1239 | if pfx+'Scale' in self.sigDict: |
---|
| 1240 | sig = self.sigDict[pfx+'Scale']*wtFr/hapData['Scale'][0] |
---|
| 1241 | else: |
---|
| 1242 | sig = -0.0001 |
---|
[3011] | 1243 | WriteCIFitem(self.fp, |
---|
[989] | 1244 | ' '+ |
---|
| 1245 | str(self.Phases[phasenam]['pId']) + |
---|
| 1246 | ' '+datablockidDict[phasenam]+ |
---|
[1037] | 1247 | ' '+G2mth.ValEsd(wtFr,sig) |
---|
[989] | 1248 | ) |
---|
[3011] | 1249 | WriteCIFitem(self.fp, 'loop_' + |
---|
[1117] | 1250 | '\n _gsas_proc_phase_R_F_factor' + |
---|
| 1251 | '\n _gsas_proc_phase_R_Fsqd_factor' + |
---|
| 1252 | '\n _gsas_proc_phase_id' + |
---|
| 1253 | '\n _gsas_proc_phase_block_id') |
---|
[1037] | 1254 | for phasenam in phasebyhistDict.get(histlbl): |
---|
| 1255 | pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':' |
---|
[3011] | 1256 | WriteCIFitem(self.fp, |
---|
[1037] | 1257 | ' '+ |
---|
| 1258 | ' '+G2mth.ValEsd(histblk[pfx+'Rf']/100.,-.00009) + |
---|
[1057] | 1259 | ' '+G2mth.ValEsd(histblk[pfx+'Rf^2']/100.,-.00009)+ |
---|
| 1260 | ' '+str(self.Phases[phasenam]['pId'])+ |
---|
| 1261 | ' '+datablockidDict[phasenam] |
---|
[1037] | 1262 | ) |
---|
| 1263 | else: |
---|
[1057] | 1264 | # single phase in this histogram |
---|
[1037] | 1265 | pfx = '0:'+str(hId)+':' |
---|
[3011] | 1266 | WriteCIFitem(self.fp, '_refine_ls_R_F_factor ','%.5f'%(histblk[pfx+'Rf']/100.)) |
---|
| 1267 | WriteCIFitem(self.fp, '_refine_ls_R_Fsqd_factor ','%.5f'%(histblk[pfx+'Rf^2']/100.)) |
---|
[989] | 1268 | |
---|
[3011] | 1269 | WriteCIFitem(self.fp, '_pd_proc_ls_prof_R_factor ','%.5f'%(histblk['R']/100.)) |
---|
| 1270 | WriteCIFitem(self.fp, '_pd_proc_ls_prof_wR_factor ','%.5f'%(histblk['wR']/100.)) |
---|
| 1271 | WriteCIFitem(self.fp, '_gsas_proc_ls_prof_R_B_factor ','%.5f'%(histblk['Rb']/100.)) |
---|
| 1272 | WriteCIFitem(self.fp, '_gsas_proc_ls_prof_wR_B_factor','%.5f'%(histblk['wRb']/100.)) |
---|
| 1273 | WriteCIFitem(self.fp, '_pd_proc_ls_prof_wR_expected','%.5f'%(histblk['wRmin']/100.)) |
---|
| 1274 | |
---|
[990] | 1275 | if histblk['Instrument Parameters'][0]['Type'][1][1] == 'X': |
---|
[3011] | 1276 | WriteCIFitem(self.fp, '_diffrn_radiation_probe','x-ray') |
---|
[990] | 1277 | pola = histblk['Instrument Parameters'][0].get('Polariz.') |
---|
| 1278 | if pola: |
---|
| 1279 | pfx = ':' + str(hId) + ':' |
---|
| 1280 | sig = self.sigDict.get(pfx+'Polariz.',-0.0009) |
---|
| 1281 | txt = G2mth.ValEsd(pola[1],sig) |
---|
[3011] | 1282 | WriteCIFitem(self.fp, '_diffrn_radiation_polarisn_ratio',txt) |
---|
[990] | 1283 | elif histblk['Instrument Parameters'][0]['Type'][1][1] == 'N': |
---|
[3011] | 1284 | WriteCIFitem(self.fp, '_diffrn_radiation_probe','neutron') |
---|
[2354] | 1285 | if 'T' in inst['Type'][0]: |
---|
| 1286 | txt = G2mth.ValEsd(inst['2-theta'][0],-0.009) |
---|
[3011] | 1287 | WriteCIFitem(self.fp, '_pd_meas_2theta_fixed',txt) |
---|
[941] | 1288 | |
---|
[990] | 1289 | # TODO: this will need help from Bob |
---|
| 1290 | #if not oneblock: |
---|
[3011] | 1291 | #WriteCIFitem(self.fp, '\n# SCATTERING FACTOR INFO') |
---|
| 1292 | #WriteCIFitem(self.fp, 'loop_ _atom_type_symbol') |
---|
[990] | 1293 | #if histblk['Instrument Parameters'][0]['Type'][1][1] == 'X': |
---|
[3011] | 1294 | # WriteCIFitem(self.fp, ' _atom_type_scat_dispersion_real') |
---|
| 1295 | # WriteCIFitem(self.fp, ' _atom_type_scat_dispersion_imag') |
---|
[990] | 1296 | # for lbl in ('a1','a2','a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c'): |
---|
[3011] | 1297 | # WriteCIFitem(self.fp, ' _atom_type_scat_Cromer_Mann_'+lbl) |
---|
[990] | 1298 | #elif histblk['Instrument Parameters'][0]['Type'][1][1] == 'N': |
---|
[3011] | 1299 | # WriteCIFitem(self.fp, ' _atom_type_scat_length_neutron') |
---|
| 1300 | #WriteCIFitem(self.fp, ' _atom_type_scat_source') |
---|
[941] | 1301 | |
---|
[3011] | 1302 | WriteCIFitem(self.fp, '_pd_proc_ls_background_function',FormatBackground(histblk['Background'],histblk['hId'])) |
---|
[990] | 1303 | |
---|
[1022] | 1304 | # TODO: this will need help from Bob |
---|
[3011] | 1305 | #WriteCIFitem(self.fp, '_exptl_absorpt_process_details','?') |
---|
| 1306 | #WriteCIFitem(self.fp, '_exptl_absorpt_correction_T_min','?') |
---|
| 1307 | #WriteCIFitem(self.fp, '_exptl_absorpt_correction_T_max','?') |
---|
[941] | 1308 | #C extinction |
---|
| 1309 | #WRITE(IUCIF,'(A)') '# Extinction correction' |
---|
| 1310 | #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_min',TEXT(1:10)) |
---|
| 1311 | #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_max',TEXT(11:20)) |
---|
| 1312 | |
---|
[1010] | 1313 | if not oneblock: # instrumental profile terms go here |
---|
[3011] | 1314 | WriteCIFitem(self.fp, '_pd_proc_ls_profile_function', |
---|
[1013] | 1315 | FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])) |
---|
[941] | 1316 | |
---|
[1010] | 1317 | #refprx = '_refln.' # mm |
---|
| 1318 | refprx = '_refln_' # normal |
---|
[1130] | 1319 | # data collection parameters for the powder dataset |
---|
[3011] | 1320 | |
---|
[1130] | 1321 | temperature = histblk['Sample Parameters'].get('Temperature') # G2 uses K |
---|
| 1322 | if not temperature: |
---|
| 1323 | T = '?' |
---|
| 1324 | else: |
---|
| 1325 | T = G2mth.ValEsd(temperature,-0.009,True) # CIF uses K |
---|
[3011] | 1326 | WriteCIFitem(self.fp, '_diffrn_ambient_temperature',T) |
---|
[1130] | 1327 | |
---|
| 1328 | pressure = histblk['Sample Parameters'].get('Pressure') #G2 uses mega-Pascal |
---|
| 1329 | if not pressure: |
---|
| 1330 | P = '?' |
---|
| 1331 | else: |
---|
| 1332 | P = G2mth.ValEsd(pressure*1000,-0.09,True) # CIF uses kilopascal |
---|
[3011] | 1333 | WriteCIFitem(self.fp, '_diffrn_ambient_pressure',P) |
---|
[1130] | 1334 | |
---|
[3011] | 1335 | WriteCIFitem(self.fp, '\n# STRUCTURE FACTOR TABLE') |
---|
[1010] | 1336 | # compute maximum intensity reflection |
---|
| 1337 | Imax = 0 |
---|
| 1338 | for phasenam in histblk['Reflection Lists']: |
---|
| 1339 | scale = self.Phases[phasenam]['Histograms'][histlbl]['Scale'][0] |
---|
[1126] | 1340 | refList = np.asarray(histblk['Reflection Lists'][phasenam]['RefList']) |
---|
| 1341 | I100 = scale*refList.T[8]*refList.T[11] |
---|
| 1342 | #Icorr = np.array([refl[13] for refl in histblk['Reflection Lists'][phasenam]])[0] |
---|
| 1343 | #FO2 = np.array([refl[8] for refl in histblk['Reflection Lists'][phasenam]]) |
---|
| 1344 | #I100 = scale*FO2*Icorr |
---|
[1010] | 1345 | Imax = max(Imax,max(I100)) |
---|
[990] | 1346 | |
---|
[3011] | 1347 | WriteCIFitem(self.fp, 'loop_') |
---|
[1010] | 1348 | if len(histblk['Reflection Lists'].keys()) > 1: |
---|
[3011] | 1349 | WriteCIFitem(self.fp, ' _pd_refln_phase_id') |
---|
| 1350 | WriteCIFitem(self.fp, ' ' + refprx + 'index_h' + |
---|
| 1351 | '\n ' + refprx + 'index_k' + |
---|
| 1352 | '\n ' + refprx + 'index_l' + |
---|
| 1353 | '\n ' + refprx + 'F_squared_meas' + |
---|
| 1354 | '\n ' + refprx + 'F_squared_calc' + |
---|
| 1355 | '\n ' + refprx + 'phase_calc' + |
---|
[1117] | 1356 | '\n _pd_refln_d_spacing') |
---|
[1010] | 1357 | if Imax > 0: |
---|
[3011] | 1358 | WriteCIFitem(self.fp, ' _gsas_i100_meas') |
---|
[941] | 1359 | |
---|
[1010] | 1360 | refcount = 0 |
---|
| 1361 | hklmin = None |
---|
| 1362 | hklmax = None |
---|
| 1363 | dmax = None |
---|
| 1364 | dmin = None |
---|
| 1365 | for phasenam in histblk['Reflection Lists']: |
---|
| 1366 | scale = self.Phases[phasenam]['Histograms'][histlbl]['Scale'][0] |
---|
| 1367 | phaseid = self.Phases[phasenam]['pId'] |
---|
[1126] | 1368 | refcount += len(histblk['Reflection Lists'][phasenam]['RefList']) |
---|
[2529] | 1369 | refList = np.asarray(histblk['Reflection Lists'][phasenam]['RefList']) |
---|
| 1370 | I100 = scale*refList.T[8]*refList.T[11] |
---|
[1126] | 1371 | for j,ref in enumerate(histblk['Reflection Lists'][phasenam]['RefList']): |
---|
[1012] | 1372 | if DEBUG: |
---|
[1068] | 1373 | print('DEBUG: skipping reflection list') |
---|
[1012] | 1374 | break |
---|
[1010] | 1375 | if hklmin is None: |
---|
| 1376 | hklmin = ref[0:3] |
---|
| 1377 | hklmax = ref[0:3] |
---|
| 1378 | dmax = dmin = ref[4] |
---|
| 1379 | if len(histblk['Reflection Lists'].keys()) > 1: |
---|
| 1380 | s = PutInCol(phaseid,2) |
---|
| 1381 | else: |
---|
| 1382 | s = "" |
---|
| 1383 | for i,hkl in enumerate(ref[0:3]): |
---|
| 1384 | hklmax[i] = max(hkl,hklmax[i]) |
---|
| 1385 | hklmin[i] = min(hkl,hklmin[i]) |
---|
| 1386 | s += PutInCol(int(hkl),4) |
---|
| 1387 | for I in ref[8:10]: |
---|
| 1388 | s += PutInCol(G2mth.ValEsd(I,-0.0009),10) |
---|
| 1389 | s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7) |
---|
| 1390 | dmax = max(dmax,ref[4]) |
---|
| 1391 | dmin = min(dmin,ref[4]) |
---|
| 1392 | s += PutInCol(G2mth.ValEsd(ref[4],-0.009),8) |
---|
| 1393 | if Imax > 0: |
---|
[1126] | 1394 | s += PutInCol(G2mth.ValEsd(100.*I100[j]/Imax,-0.09),6) |
---|
[3011] | 1395 | WriteCIFitem(self.fp, " "+s) |
---|
[1010] | 1396 | |
---|
[1030] | 1397 | WriteReflStat(refcount,hklmin,hklmax,dmin,dmax,len(histblk['Reflection Lists'])) |
---|
[3011] | 1398 | WriteCIFitem(self.fp, '\n# POWDER DATA TABLE') |
---|
[1010] | 1399 | # is data fixed step? If the step varies by <0.01% treat as fixed step |
---|
| 1400 | steps = histblk['Data'][0][1:] - histblk['Data'][0][:-1] |
---|
| 1401 | if abs(max(steps)-min(steps)) > abs(max(steps))/10000.: |
---|
| 1402 | fixedstep = False |
---|
| 1403 | else: |
---|
| 1404 | fixedstep = True |
---|
| 1405 | |
---|
[2354] | 1406 | zero = None |
---|
| 1407 | if fixedstep and 'T' not in inst['Type'][0]: # and not TOF |
---|
[3011] | 1408 | WriteCIFitem(self.fp, '_pd_meas_2theta_range_min', G2mth.ValEsd(histblk['Data'][0][0],-0.00009)) |
---|
| 1409 | WriteCIFitem(self.fp, '_pd_meas_2theta_range_max', G2mth.ValEsd(histblk['Data'][0][-1],-0.00009)) |
---|
| 1410 | WriteCIFitem(self.fp, '_pd_meas_2theta_range_inc', G2mth.ValEsd(steps.sum()/len(steps),-0.00009)) |
---|
[1010] | 1411 | # zero correct, if defined |
---|
| 1412 | zerolst = histblk['Instrument Parameters'][0].get('Zero') |
---|
| 1413 | if zerolst: zero = zerolst[1] |
---|
| 1414 | zero = self.parmDict.get('Zero',zero) |
---|
| 1415 | if zero: |
---|
[3011] | 1416 | WriteCIFitem(self.fp, '_pd_proc_2theta_range_min', G2mth.ValEsd(histblk['Data'][0][0]-zero,-0.00009)) |
---|
| 1417 | WriteCIFitem(self.fp, '_pd_proc_2theta_range_max', G2mth.ValEsd(histblk['Data'][0][-1]-zero,-0.00009)) |
---|
| 1418 | WriteCIFitem(self.fp, '_pd_proc_2theta_range_inc', G2mth.ValEsd(steps.sum()/len(steps),-0.00009)) |
---|
| 1419 | |
---|
[1010] | 1420 | if zero: |
---|
[3011] | 1421 | WriteCIFitem(self.fp, '_pd_proc_number_of_points', str(len(histblk['Data'][0]))) |
---|
[1010] | 1422 | else: |
---|
[3011] | 1423 | WriteCIFitem(self.fp, '_pd_meas_number_of_points', str(len(histblk['Data'][0]))) |
---|
| 1424 | WriteCIFitem(self.fp, '\nloop_') |
---|
| 1425 | # WriteCIFitem(self.fp, ' _pd_proc_d_spacing') # need easy way to get this |
---|
[941] | 1426 | if not fixedstep: |
---|
[1010] | 1427 | if zero: |
---|
[3011] | 1428 | WriteCIFitem(self.fp, ' _pd_proc_2theta_corrected') |
---|
[2354] | 1429 | elif 'T' in inst['Type'][0]: # and not TOF |
---|
[3011] | 1430 | WriteCIFitem(self.fp, ' _pd_meas_time_of_flight') |
---|
[941] | 1431 | else: |
---|
[3011] | 1432 | WriteCIFitem(self.fp, ' _pd_meas_2theta_scan') |
---|
[1022] | 1433 | # at least for now, always report weights. |
---|
[1010] | 1434 | #if countsdata: |
---|
[3011] | 1435 | # WriteCIFitem(self.fp, ' _pd_meas_counts_total') |
---|
[1010] | 1436 | #else: |
---|
[3011] | 1437 | WriteCIFitem(self.fp, ' _pd_meas_intensity_total') |
---|
| 1438 | WriteCIFitem(self.fp, ' _pd_calc_intensity_total') |
---|
| 1439 | WriteCIFitem(self.fp, ' _pd_proc_intensity_bkg_calc') |
---|
| 1440 | WriteCIFitem(self.fp, ' _pd_proc_ls_weight') |
---|
[1022] | 1441 | maxY = max(histblk['Data'][1].max(),histblk['Data'][3].max()) |
---|
| 1442 | if maxY < 0: maxY *= -10 # this should never happen, but... |
---|
| 1443 | ndec = max(0,10-int(np.log10(maxY))-1) # 10 sig figs should be enough |
---|
| 1444 | maxSU = histblk['Data'][2].max() |
---|
| 1445 | if maxSU < 0: maxSU *= -1 # this should never happen, but... |
---|
| 1446 | ndecSU = max(0,8-int(np.log10(maxSU))-1) # 8 sig figs should be enough |
---|
| 1447 | lowlim,highlim = histblk['Limits'][1] |
---|
| 1448 | |
---|
[1029] | 1449 | if DEBUG: |
---|
[1068] | 1450 | print('DEBUG: skipping profile list') |
---|
[3011] | 1451 | else: |
---|
[1029] | 1452 | for x,yobs,yw,ycalc,ybkg in zip(histblk['Data'][0], |
---|
| 1453 | histblk['Data'][1], |
---|
| 1454 | histblk['Data'][2], |
---|
| 1455 | histblk['Data'][3], |
---|
| 1456 | histblk['Data'][4]): |
---|
| 1457 | if lowlim <= x <= highlim: |
---|
| 1458 | pass |
---|
| 1459 | else: |
---|
| 1460 | yw = 0.0 # show the point is not in use |
---|
[3011] | 1461 | |
---|
[1029] | 1462 | if fixedstep: |
---|
| 1463 | s = "" |
---|
[2354] | 1464 | elif zero: |
---|
| 1465 | s = PutInCol(G2mth.ValEsd(x-zero,-0.00009),10) |
---|
[1029] | 1466 | else: |
---|
[2354] | 1467 | s = PutInCol(G2mth.ValEsd(x,-0.00009),10) |
---|
[1029] | 1468 | s += PutInCol(Yfmt(ndec,yobs),12) |
---|
| 1469 | s += PutInCol(Yfmt(ndec,ycalc),12) |
---|
| 1470 | s += PutInCol(Yfmt(ndec,ybkg),11) |
---|
| 1471 | s += PutInCol(Yfmt(ndecSU,yw),9) |
---|
[3011] | 1472 | WriteCIFitem(self.fp, " "+s) |
---|
[1022] | 1473 | |
---|
[938] | 1474 | def WriteSingleXtalData(histlbl): |
---|
[1074] | 1475 | 'Write out the selected single crystal histogram info' |
---|
[956] | 1476 | histblk = self.Histograms[histlbl] |
---|
[1127] | 1477 | |
---|
[1010] | 1478 | #refprx = '_refln.' # mm |
---|
[941] | 1479 | refprx = '_refln_' # normal |
---|
[1010] | 1480 | |
---|
[3011] | 1481 | WriteCIFitem(self.fp, '\n# STRUCTURE FACTOR TABLE') |
---|
| 1482 | WriteCIFitem(self.fp, 'loop_' + |
---|
| 1483 | '\n ' + refprx + 'index_h' + |
---|
| 1484 | '\n ' + refprx + 'index_k' + |
---|
[1117] | 1485 | '\n ' + refprx + 'index_l' + |
---|
[3011] | 1486 | '\n ' + refprx + 'F_squared_meas' + |
---|
| 1487 | '\n ' + refprx + 'F_squared_sigma' + |
---|
| 1488 | '\n ' + refprx + 'F_squared_calc' + |
---|
[1117] | 1489 | '\n ' + refprx + 'phase_calc' |
---|
[1010] | 1490 | ) |
---|
[938] | 1491 | |
---|
[1010] | 1492 | hklmin = None |
---|
| 1493 | hklmax = None |
---|
| 1494 | dmax = None |
---|
| 1495 | dmin = None |
---|
[1126] | 1496 | refcount = len(histblk['Data']['RefList']) |
---|
| 1497 | for ref in histblk['Data']['RefList']: |
---|
[2136] | 1498 | if ref[3] <= 0: #skip user rejected reflections (mul <= 0) |
---|
[1782] | 1499 | continue |
---|
[1010] | 1500 | s = " " |
---|
| 1501 | if hklmin is None: |
---|
| 1502 | hklmin = ref[0:3] |
---|
| 1503 | hklmax = ref[0:3] |
---|
| 1504 | dmax = dmin = ref[4] |
---|
| 1505 | for i,hkl in enumerate(ref[0:3]): |
---|
| 1506 | hklmax[i] = max(hkl,hklmax[i]) |
---|
| 1507 | hklmin[i] = min(hkl,hklmin[i]) |
---|
| 1508 | s += PutInCol(int(hkl),4) |
---|
[1074] | 1509 | if ref[5] == 0.0: |
---|
| 1510 | s += PutInCol(G2mth.ValEsd(ref[8],0),12) |
---|
| 1511 | s += PutInCol('.',10) |
---|
| 1512 | s += PutInCol(G2mth.ValEsd(ref[9],0),12) |
---|
| 1513 | s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7) |
---|
| 1514 | else: |
---|
| 1515 | sig = ref[6] * ref[8] / ref[5] |
---|
| 1516 | s += PutInCol(G2mth.ValEsd(ref[8],-abs(sig/10)),12) |
---|
| 1517 | s += PutInCol(G2mth.ValEsd(sig,-abs(sig)/10.),10) |
---|
| 1518 | s += PutInCol(G2mth.ValEsd(ref[9],-abs(sig/10)),12) |
---|
[1010] | 1519 | s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7) |
---|
| 1520 | dmax = max(dmax,ref[4]) |
---|
| 1521 | dmin = min(dmin,ref[4]) |
---|
[3011] | 1522 | WriteCIFitem(self.fp, s) |
---|
[1127] | 1523 | if not self.quickmode: # statistics only in a full CIF |
---|
| 1524 | WriteReflStat(refcount,hklmin,hklmax,dmin,dmax) |
---|
[1658] | 1525 | hId = histblk['hId'] |
---|
| 1526 | hfx = '0:'+str(hId)+':' |
---|
| 1527 | phfx = '%d:%d:'%(0,hId) |
---|
| 1528 | extType,extModel,extParms = self.Phases[phasenam]['Histograms'][histlbl]['Extinction'] |
---|
| 1529 | if extModel != 'None': |
---|
[3011] | 1530 | WriteCIFitem(self.fp, '# Extinction scaled by 1.e5') |
---|
| 1531 | WriteCIFitem(self.fp, '_refine_ls_extinction_method','Becker-Coppens %s %s'%(extModel,extType)) |
---|
[1658] | 1532 | sig = -1.e-3 |
---|
| 1533 | if extModel == 'Primary': |
---|
| 1534 | parm = extParms['Ep'][0]*1.e5 |
---|
| 1535 | if extParms['Ep'][1]: |
---|
| 1536 | sig = self.sigDict[phfx+'Ep']*1.e5 |
---|
| 1537 | text = G2mth.ValEsd(parm,sig) |
---|
| 1538 | elif extModel == 'Secondary Type I': |
---|
| 1539 | parm = extParms['Eg'][0]*1.e5 |
---|
| 1540 | if extParms['Eg'][1]: |
---|
| 1541 | sig = self.sigDict[phfx+'Eg']*1.e5 |
---|
| 1542 | text = G2mth.ValEsd(parm,sig) |
---|
| 1543 | elif extModel == 'Secondary Type II': |
---|
| 1544 | parm = extParms['Es'][0]*1.e5 |
---|
| 1545 | if extParms['Es'][1]: |
---|
| 1546 | sig = self.sigDict[phfx+'Es']*1.e5 |
---|
| 1547 | text = G2mth.ValEsd(parm,sig) |
---|
| 1548 | elif extModel == 'Secondary Type I & II': |
---|
| 1549 | parm = extParms['Eg'][0]*1.e5 |
---|
| 1550 | if extParms['Es'][1]: |
---|
| 1551 | sig = self.sigDict[phfx+'Es']*1.e5 |
---|
| 1552 | text = G2mth.ValEsd(parm,sig) |
---|
| 1553 | sig = -1.0e-3 |
---|
| 1554 | parm = extParms['Es'][0]*1.e5 |
---|
| 1555 | if extParms['Es'][1]: |
---|
| 1556 | sig = self.sigDict[phfx+'Es']*1.e5 |
---|
| 1557 | text += G2mth.ValEsd(parm,sig) |
---|
[3011] | 1558 | WriteCIFitem(self.fp, '_refine_ls_extinction_coef',text) |
---|
| 1559 | WriteCIFitem(self.fp, '_refine_ls_extinction_expression','Becker & Coppens (1974). Acta Cryst. A30, 129-147') |
---|
[1658] | 1560 | |
---|
[3011] | 1561 | WriteCIFitem(self.fp, '_refine_ls_wR_factor_gt ','%.4f'%(histblk['wR']/100.)) |
---|
| 1562 | WriteCIFitem(self.fp, '_refine_ls_R_factor_gt ','%.4f'%(histblk[hfx+'Rf']/100.)) |
---|
| 1563 | WriteCIFitem(self.fp, '_refine_ls_R_Fsqd_factor ','%.4f'%(histblk[hfx+'Rf^2']/100.)) |
---|
[1057] | 1564 | def EditAuthor(event=None): |
---|
[1074] | 1565 | 'dialog to edit the CIF author info' |
---|
[1057] | 1566 | 'Edit the CIF author name' |
---|
[1831] | 1567 | dlg = G2G.SingleStringDialog(self.G2frame, |
---|
[1057] | 1568 | 'Get CIF Author', |
---|
| 1569 | 'Provide CIF Author name (Last, First)', |
---|
| 1570 | value=self.author) |
---|
| 1571 | if not dlg.Show(): |
---|
| 1572 | dlg.Destroy() |
---|
| 1573 | return False # cancel was pressed |
---|
| 1574 | self.author = dlg.GetValue() |
---|
[2449] | 1575 | self.shortauthorname = self.author.replace(',','').replace(' ','')[:20] |
---|
[1057] | 1576 | dlg.Destroy() |
---|
| 1577 | try: |
---|
| 1578 | self.OverallParms['Controls']["Author"] = self.author # save for future |
---|
| 1579 | except KeyError: |
---|
| 1580 | pass |
---|
| 1581 | return True |
---|
[2449] | 1582 | |
---|
[1067] | 1583 | def EditInstNames(event=None): |
---|
[1057] | 1584 | 'Provide a dialog for editing instrument names' |
---|
| 1585 | dictlist = [] |
---|
| 1586 | keylist = [] |
---|
| 1587 | lbllist = [] |
---|
| 1588 | for hist in self.Histograms: |
---|
[3011] | 1589 | if hist.startswith("PWDR"): |
---|
[1057] | 1590 | key2 = "Sample Parameters" |
---|
| 1591 | d = self.Histograms[hist][key2] |
---|
[3011] | 1592 | elif hist.startswith("HKLF"): |
---|
[1057] | 1593 | key2 = "Instrument Parameters" |
---|
| 1594 | d = self.Histograms[hist][key2][0] |
---|
[3011] | 1595 | |
---|
[1057] | 1596 | lbllist.append(hist) |
---|
| 1597 | dictlist.append(d) |
---|
| 1598 | keylist.append('InstrName') |
---|
| 1599 | instrname = d.get('InstrName') |
---|
| 1600 | if instrname is None: |
---|
| 1601 | d['InstrName'] = '' |
---|
[2516] | 1602 | return G2G.CallScrolledMultiEditor( |
---|
[1057] | 1603 | self.G2frame,dictlist,keylist, |
---|
| 1604 | prelbl=range(1,len(dictlist)+1), |
---|
| 1605 | postlbl=lbllist, |
---|
| 1606 | title='Instrument names', |
---|
[1067] | 1607 | header="Edit instrument names. Note that a non-blank\nname is required for all histograms", |
---|
[2516] | 1608 | CopyButton=True,ASCIIonly=True) |
---|
[3011] | 1609 | |
---|
[1067] | 1610 | def EditRanges(event): |
---|
[1074] | 1611 | '''Edit the bond distance/angle search range; phase is determined from |
---|
| 1612 | a pointer placed in the button object (.phasedict) that references the |
---|
| 1613 | phase dictionary |
---|
| 1614 | ''' |
---|
[1067] | 1615 | but = event.GetEventObject() |
---|
| 1616 | phasedict = but.phasedict |
---|
[3000] | 1617 | dlg = G2G.DisAglDialog( |
---|
[1126] | 1618 | self.G2frame, |
---|
[3011] | 1619 | phasedict['General']['DisAglCtls'], # edited |
---|
[1126] | 1620 | phasedict['General'], # defaults |
---|
| 1621 | ) |
---|
[1067] | 1622 | if dlg.ShowModal() == wx.ID_OK: |
---|
| 1623 | phasedict['General']['DisAglCtls'] = dlg.GetData() |
---|
| 1624 | dlg.Destroy() |
---|
[3011] | 1625 | |
---|
[1067] | 1626 | def EditCIFDefaults(): |
---|
[1074] | 1627 | '''Fills the CIF Defaults window with controls for editing various CIF export |
---|
| 1628 | parameters (mostly related to templates). |
---|
| 1629 | ''' |
---|
[1067] | 1630 | self.cifdefs.DestroyChildren() |
---|
| 1631 | self.cifdefs.SetTitle('Edit CIF settings') |
---|
[1057] | 1632 | vbox = wx.BoxSizer(wx.VERTICAL) |
---|
[2543] | 1633 | vbox.Add(wx.StaticText(self.cifdefs, wx.ID_ANY,'Creating file '+self.filename)) |
---|
[1068] | 1634 | but = wx.Button(self.cifdefs, wx.ID_ANY,'Edit CIF Author') |
---|
| 1635 | but.Bind(wx.EVT_BUTTON,EditAuthor) |
---|
| 1636 | vbox.Add(but,0,wx.ALIGN_CENTER,3) |
---|
| 1637 | but = wx.Button(self.cifdefs, wx.ID_ANY,'Edit Instrument Name(s)') |
---|
| 1638 | but.Bind(wx.EVT_BUTTON,EditInstNames) |
---|
| 1639 | vbox.Add(but,0,wx.ALIGN_CENTER,3) |
---|
[1067] | 1640 | cpnl = wxscroll.ScrolledPanel(self.cifdefs,size=(300,300)) |
---|
[1057] | 1641 | cbox = wx.BoxSizer(wx.VERTICAL) |
---|
[3011] | 1642 | G2G.HorizontalLine(cbox,cpnl) |
---|
[1067] | 1643 | cbox.Add( |
---|
| 1644 | CIFtemplateSelect(self.cifdefs, |
---|
| 1645 | cpnl,'publ',self.OverallParms['Controls'], |
---|
| 1646 | EditCIFDefaults, |
---|
| 1647 | "Publication (overall) template", |
---|
| 1648 | ), |
---|
| 1649 | 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) |
---|
| 1650 | for phasenam in sorted(self.Phases.keys()): |
---|
[3011] | 1651 | G2G.HorizontalLine(cbox,cpnl) |
---|
[1067] | 1652 | title = 'Phase '+phasenam |
---|
[3011] | 1653 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
[1067] | 1654 | cbox.Add( |
---|
| 1655 | CIFtemplateSelect(self.cifdefs, |
---|
| 1656 | cpnl,'phase',phasedict['General'], |
---|
| 1657 | EditCIFDefaults, |
---|
[1068] | 1658 | title, |
---|
| 1659 | phasenam), |
---|
[1067] | 1660 | 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) |
---|
| 1661 | cpnl.SetSizer(cbox) |
---|
[3011] | 1662 | if phasedict['General']['Type'] == 'nuclear': |
---|
[1081] | 1663 | but = wx.Button(cpnl, wx.ID_ANY,'Edit distance/angle ranges') |
---|
| 1664 | cbox.Add(but,0,wx.ALIGN_LEFT,0) |
---|
| 1665 | cbox.Add((-1,2)) |
---|
| 1666 | but.phasedict = self.Phases[phasenam] # set a pointer to current phase info |
---|
| 1667 | but.Bind(wx.EVT_BUTTON,EditRanges) # phase bond/angle ranges |
---|
| 1668 | but = wx.Button(cpnl, wx.ID_ANY,'Set distance/angle publication flags') |
---|
[3011] | 1669 | but.phase = phasenam # set a pointer to current phase info |
---|
[1081] | 1670 | but.Bind(wx.EVT_BUTTON,SelectDisAglFlags) # phase bond/angle ranges |
---|
| 1671 | cbox.Add(but,0,wx.ALIGN_LEFT,0) |
---|
[1067] | 1672 | cbox.Add((-1,2)) |
---|
| 1673 | for i in sorted(self.powderDict.keys()): |
---|
[3011] | 1674 | G2G.HorizontalLine(cbox,cpnl) |
---|
[1067] | 1675 | hist = self.powderDict[i] |
---|
| 1676 | histblk = self.Histograms[hist] |
---|
| 1677 | title = 'Powder dataset '+hist[5:] |
---|
| 1678 | cbox.Add( |
---|
| 1679 | CIFtemplateSelect(self.cifdefs, |
---|
| 1680 | cpnl,'powder',histblk["Sample Parameters"], |
---|
| 1681 | EditCIFDefaults, |
---|
[1068] | 1682 | title, |
---|
| 1683 | histblk["Sample Parameters"]['InstrName']), |
---|
[1067] | 1684 | 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) |
---|
| 1685 | for i in sorted(self.xtalDict.keys()): |
---|
[3011] | 1686 | G2G.HorizontalLine(cbox,cpnl) |
---|
[1067] | 1687 | hist = self.xtalDict[i] |
---|
| 1688 | histblk = self.Histograms[hist] |
---|
| 1689 | title = 'Single Xtal dataset '+hist[5:] |
---|
| 1690 | cbox.Add( |
---|
| 1691 | CIFtemplateSelect(self.cifdefs, |
---|
| 1692 | cpnl,'single',histblk["Instrument Parameters"][0], |
---|
| 1693 | EditCIFDefaults, |
---|
[1068] | 1694 | title, |
---|
| 1695 | histblk["Instrument Parameters"][0]['InstrName']), |
---|
[1067] | 1696 | 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) |
---|
[1077] | 1697 | cpnl.SetSizer(cbox) |
---|
[1057] | 1698 | cpnl.SetAutoLayout(1) |
---|
| 1699 | cpnl.SetupScrolling() |
---|
[1067] | 1700 | #cpnl.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded) # needed if sizes change |
---|
[1057] | 1701 | cpnl.Layout() |
---|
| 1702 | |
---|
| 1703 | vbox.Add(cpnl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 0) |
---|
| 1704 | btnsizer = wx.StdDialogButtonSizer() |
---|
[1067] | 1705 | btn = wx.Button(self.cifdefs, wx.ID_OK, "Create CIF") |
---|
[1057] | 1706 | btn.SetDefault() |
---|
| 1707 | btnsizer.AddButton(btn) |
---|
[1067] | 1708 | btn = wx.Button(self.cifdefs, wx.ID_CANCEL) |
---|
[1057] | 1709 | btnsizer.AddButton(btn) |
---|
| 1710 | btnsizer.Realize() |
---|
| 1711 | vbox.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5) |
---|
[1067] | 1712 | self.cifdefs.SetSizer(vbox) |
---|
| 1713 | vbox.Fit(self.cifdefs) |
---|
| 1714 | self.cifdefs.Layout() |
---|
[3011] | 1715 | |
---|
[1077] | 1716 | def OnToggleButton(event): |
---|
| 1717 | 'Respond to press of ToggleButton in SelectDisAglFlags' |
---|
| 1718 | but = event.GetEventObject() |
---|
[3011] | 1719 | if but.GetValue(): |
---|
[1077] | 1720 | but.DisAglSel[but.key] = True |
---|
| 1721 | else: |
---|
| 1722 | try: |
---|
| 1723 | del but.DisAglSel[but.key] |
---|
| 1724 | except KeyError: |
---|
| 1725 | pass |
---|
| 1726 | def keepTrue(event): |
---|
| 1727 | event.GetEventObject().SetValue(True) |
---|
| 1728 | def keepFalse(event): |
---|
| 1729 | event.GetEventObject().SetValue(False) |
---|
[3011] | 1730 | |
---|
[1077] | 1731 | def SelectDisAglFlags(event): |
---|
| 1732 | 'Select Distance/Angle use flags for the selected phase' |
---|
| 1733 | phasenam = event.GetEventObject().phase |
---|
| 1734 | phasedict = self.Phases[phasenam] |
---|
[2567] | 1735 | SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps(phasedict['General']['SGData']) |
---|
[1077] | 1736 | generalData = phasedict['General'] |
---|
| 1737 | # create a dict for storing Pub flag for bonds/angles, if needed |
---|
| 1738 | if phasedict['General'].get("DisAglHideFlag") is None: |
---|
| 1739 | phasedict['General']["DisAglHideFlag"] = {} |
---|
| 1740 | DisAngSel = phasedict['General']["DisAglHideFlag"] |
---|
[1057] | 1741 | |
---|
[1077] | 1742 | cx,ct,cs,cia = phasedict['General']['AtomPtrs'] |
---|
| 1743 | cn = ct-1 |
---|
| 1744 | cfrac = cx+3 |
---|
| 1745 | DisAglData = {} |
---|
| 1746 | # create a list of atoms, but skip atoms with zero occupancy |
---|
| 1747 | xyz = [] |
---|
[3011] | 1748 | fpfx = str(phasedict['pId'])+'::Afrac:' |
---|
[1077] | 1749 | for i,atom in enumerate(phasedict['Atoms']): |
---|
| 1750 | if self.parmDict.get(fpfx+str(i),atom[cfrac]) == 0.0: continue |
---|
| 1751 | xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3]) |
---|
[1126] | 1752 | if 'DisAglCtls' not in generalData: |
---|
| 1753 | # should not be used, since DisAglDialog should be called |
---|
| 1754 | # for all phases before getting here |
---|
[3000] | 1755 | dlg = G2G.DisAglDialog( |
---|
[1126] | 1756 | self.cifdefs, |
---|
| 1757 | {}, |
---|
| 1758 | generalData) |
---|
[1077] | 1759 | if dlg.ShowModal() == wx.ID_OK: |
---|
[1126] | 1760 | generalData['DisAglCtls'] = dlg.GetData() |
---|
[1077] | 1761 | else: |
---|
| 1762 | dlg.Destroy() |
---|
| 1763 | return |
---|
| 1764 | dlg.Destroy() |
---|
| 1765 | dlg = wx.Dialog( |
---|
| 1766 | self.G2frame, |
---|
| 1767 | style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) |
---|
| 1768 | vbox = wx.BoxSizer(wx.VERTICAL) |
---|
| 1769 | txt = wx.StaticText(dlg,wx.ID_ANY,'Searching distances for phase '+phasenam |
---|
| 1770 | +'\nPlease wait...') |
---|
| 1771 | vbox.Add(txt,0,wx.ALL|wx.EXPAND) |
---|
| 1772 | dlg.SetSizer(vbox) |
---|
| 1773 | dlg.CenterOnParent() |
---|
| 1774 | dlg.Show() # post "please wait" |
---|
| 1775 | wx.BeginBusyCursor() # and change cursor |
---|
| 1776 | |
---|
| 1777 | DisAglData['OrigAtoms'] = xyz |
---|
| 1778 | DisAglData['TargAtoms'] = xyz |
---|
[2567] | 1779 | SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps( |
---|
[1077] | 1780 | generalData['SGData']) |
---|
| 1781 | |
---|
[2567] | 1782 | # xpandSGdata = generalData['SGData'].copy() |
---|
| 1783 | # xpandSGdata.update({'SGOps':symOpList, |
---|
| 1784 | # 'SGInv':False, |
---|
| 1785 | # 'SGLatt':'P', |
---|
| 1786 | # 'SGCen':np.array([[0, 0, 0]]),}) |
---|
| 1787 | # DisAglData['SGData'] = xpandSGdata |
---|
| 1788 | DisAglData['SGData'] = generalData['SGData'].copy() |
---|
[1077] | 1789 | |
---|
| 1790 | DisAglData['Cell'] = generalData['Cell'][1:] #+ volume |
---|
| 1791 | if 'pId' in phasedict: |
---|
| 1792 | DisAglData['pId'] = phasedict['pId'] |
---|
| 1793 | DisAglData['covData'] = self.OverallParms['Covariance'] |
---|
| 1794 | try: |
---|
[1126] | 1795 | AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle( |
---|
| 1796 | generalData['DisAglCtls'], |
---|
| 1797 | DisAglData) |
---|
[1077] | 1798 | except KeyError: # inside DistAngle for missing atom types in DisAglCtls |
---|
| 1799 | print('**** ERROR - try again but do "Reset" to fill in missing atom types ****') |
---|
| 1800 | wx.EndBusyCursor() |
---|
| 1801 | txt.SetLabel('Set publication flags for distances and angles in\nphase '+phasenam) |
---|
[3011] | 1802 | vbox.Add((5,5)) |
---|
[1077] | 1803 | vbox.Add(wx.StaticText(dlg,wx.ID_ANY, |
---|
| 1804 | 'The default is to flag all distances and angles as to be'+ |
---|
| 1805 | '\npublished. Change this by pressing appropriate buttons.'), |
---|
| 1806 | 0,wx.ALL|wx.EXPAND) |
---|
| 1807 | hbox = wx.BoxSizer(wx.HORIZONTAL) |
---|
| 1808 | vbox.Add(hbox) |
---|
| 1809 | hbox.Add(wx.StaticText(dlg,wx.ID_ANY,'Button appearance: ')) |
---|
| 1810 | but = wx.ToggleButton(dlg,wx.ID_ANY,'Publish') |
---|
| 1811 | but.Bind(wx.EVT_TOGGLEBUTTON,keepFalse) |
---|
| 1812 | hbox.Add(but) |
---|
| 1813 | but = wx.ToggleButton(dlg,wx.ID_ANY,"Don't publish") |
---|
| 1814 | but.Bind(wx.EVT_TOGGLEBUTTON,keepTrue) |
---|
| 1815 | hbox.Add(but) |
---|
| 1816 | but.SetValue(True) |
---|
[3011] | 1817 | G2G.HorizontalLine(vbox,dlg) |
---|
| 1818 | |
---|
[1077] | 1819 | cpnl = wxscroll.ScrolledPanel(dlg,size=(400,300)) |
---|
| 1820 | cbox = wx.BoxSizer(wx.VERTICAL) |
---|
| 1821 | for c in sorted(DistArray): |
---|
| 1822 | karr = [] |
---|
| 1823 | UsedCols = {} |
---|
| 1824 | cbox.Add(wx.StaticText(cpnl,wx.ID_ANY, |
---|
| 1825 | 'distances to/angles around atom '+AtomLabels[c])) |
---|
| 1826 | #dbox = wx.GridBagSizer(hgap=5) |
---|
| 1827 | dbox = wx.GridBagSizer() |
---|
| 1828 | for i,D in enumerate(DistArray[c]): |
---|
| 1829 | karr.append(tuple(D[0:3])) |
---|
| 1830 | val = "{:.2f}".format(D[3]) |
---|
| 1831 | sym = " [{:d} {:d} {:d}]".format(*D[1]) + " #{:d}".format(D[2]) |
---|
| 1832 | dbox.Add(wx.StaticText(cpnl,wx.ID_ANY,AtomLabels[D[0]]), |
---|
| 1833 | (i+1,0) |
---|
[3011] | 1834 | ) |
---|
[1077] | 1835 | dbox.Add(wx.StaticText(cpnl,wx.ID_ANY,sym), |
---|
| 1836 | (i+1,1) |
---|
| 1837 | ) |
---|
| 1838 | but = wx.ToggleButton(cpnl,wx.ID_ANY,val) |
---|
| 1839 | but.key = (c,karr[-1]) |
---|
| 1840 | but.DisAglSel = DisAngSel |
---|
| 1841 | if DisAngSel.get(but.key): but.SetValue(True) |
---|
| 1842 | but.Bind(wx.EVT_TOGGLEBUTTON,OnToggleButton) |
---|
| 1843 | dbox.Add(but,(i+1,2),border=1) |
---|
| 1844 | for i,D in enumerate(AngArray[c]): |
---|
| 1845 | val = "{:.1f}".format(D[2][0]) |
---|
| 1846 | but = wx.ToggleButton(cpnl,wx.ID_ANY,val) |
---|
| 1847 | but.key = (karr[D[0]],c,karr[D[1]]) |
---|
| 1848 | but.DisAglSel = DisAngSel |
---|
| 1849 | if DisAngSel.get(but.key): but.SetValue(True) |
---|
| 1850 | but.Bind(wx.EVT_TOGGLEBUTTON,OnToggleButton) |
---|
| 1851 | dbox.Add(but,(D[0]+1,D[1]+3),border=1) |
---|
| 1852 | UsedCols[D[1]+3] = True |
---|
| 1853 | for i,D in enumerate(DistArray[c][:-1]): # label columns that are used |
---|
| 1854 | if UsedCols.get(i+3): |
---|
| 1855 | dbox.Add(wx.StaticText(cpnl,wx.ID_ANY,AtomLabels[D[0]]), |
---|
| 1856 | (0,i+3), |
---|
| 1857 | flag=wx.ALIGN_CENTER |
---|
| 1858 | ) |
---|
| 1859 | dbox.Add(wx.StaticText(cpnl,wx.ID_ANY,'distance'), |
---|
| 1860 | (0,2), |
---|
| 1861 | flag=wx.ALIGN_CENTER |
---|
| 1862 | ) |
---|
| 1863 | cbox.Add(dbox) |
---|
[3011] | 1864 | G2G.HorizontalLine(cbox,cpnl) |
---|
[1077] | 1865 | cpnl.SetSizer(cbox) |
---|
| 1866 | cpnl.SetAutoLayout(1) |
---|
| 1867 | cpnl.SetupScrolling() |
---|
| 1868 | #cpnl.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded) # needed if sizes change |
---|
| 1869 | cpnl.Layout() |
---|
| 1870 | |
---|
| 1871 | vbox.Add(cpnl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 0) |
---|
| 1872 | |
---|
| 1873 | btnsizer = wx.StdDialogButtonSizer() |
---|
| 1874 | btn = wx.Button(dlg, wx.ID_OK, "Done") |
---|
| 1875 | btn.SetDefault() |
---|
| 1876 | btnsizer.AddButton(btn) |
---|
| 1877 | btnsizer.Realize() |
---|
| 1878 | vbox.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5) |
---|
| 1879 | dlg.SetSizer(vbox) |
---|
| 1880 | vbox.Fit(dlg) |
---|
| 1881 | dlg.Layout() |
---|
[3011] | 1882 | |
---|
[1077] | 1883 | dlg.CenterOnParent() |
---|
| 1884 | dlg.ShowModal() |
---|
[3011] | 1885 | |
---|
[1067] | 1886 | #================================================================================= |
---|
[2449] | 1887 | #===== end of function definitions for _Exporter ================================= |
---|
| 1888 | #================================================================================= |
---|
[2433] | 1889 | # make sure required information is present |
---|
| 1890 | self.CIFdate = dt.datetime.strftime(dt.datetime.now(),"%Y-%m-%dT%H:%M") |
---|
[3011] | 1891 | if not self.CIFname: # Get a name for the CIF. If not defined, use the GPX name (save, if that is needed). |
---|
[2449] | 1892 | if not self.G2frame.GSASprojectfile: |
---|
| 1893 | self.G2frame.OnFileSaveas(None) |
---|
[2433] | 1894 | if not self.G2frame.GSASprojectfile: return |
---|
| 1895 | self.CIFname = os.path.splitext( |
---|
| 1896 | os.path.split(self.G2frame.GSASprojectfile)[1] |
---|
| 1897 | )[0] |
---|
| 1898 | self.CIFname = self.CIFname.replace(' ','') |
---|
[2516] | 1899 | # replace non-ASCII characters in CIFname with dots |
---|
| 1900 | s = '' |
---|
| 1901 | for c in self.CIFname: |
---|
| 1902 | if ord(c) < 128: |
---|
| 1903 | s += c |
---|
| 1904 | else: |
---|
| 1905 | s += '.' |
---|
| 1906 | self.CIFname = s |
---|
| 1907 | # load saved CIF author name |
---|
[2433] | 1908 | try: |
---|
| 1909 | self.author = self.OverallParms['Controls'].get("Author",'').strip() |
---|
| 1910 | except KeyError: |
---|
| 1911 | pass |
---|
[2516] | 1912 | #================================================================= |
---|
[3011] | 1913 | # write quick CIFs |
---|
[2516] | 1914 | #================================================================= |
---|
| 1915 | if phaseOnly: #====Phase only CIF ================================ |
---|
[2543] | 1916 | print('Writing CIF output to file '+self.filename) |
---|
[2867] | 1917 | #self.OpenFile() |
---|
[2433] | 1918 | oneblock = True |
---|
| 1919 | self.quickmode = True |
---|
| 1920 | self.Write(' ') |
---|
| 1921 | self.Write(70*'#') |
---|
[3011] | 1922 | WriteCIFitem(self.fp, 'data_'+self.CIFname) |
---|
[2433] | 1923 | #phaseblk = self.Phases[phaseOnly] # pointer to current phase info |
---|
| 1924 | # report the phase info |
---|
| 1925 | WritePhaseInfo(phaseOnly) |
---|
[2867] | 1926 | #self.CloseFile() |
---|
[2433] | 1927 | return |
---|
[2516] | 1928 | elif histOnly: #====Histogram only CIF ================================ |
---|
[2543] | 1929 | print('Writing CIF output to file '+self.filename) |
---|
[2867] | 1930 | #self.OpenFile() |
---|
[2433] | 1931 | hist = histOnly |
---|
[2867] | 1932 | #histname = histOnly.replace(' ','') |
---|
[2433] | 1933 | oneblock = True |
---|
[2449] | 1934 | self.quickmode = True |
---|
[2433] | 1935 | self.ifHKLF = False |
---|
| 1936 | self.ifPWDR = True |
---|
| 1937 | self.Write(' ') |
---|
| 1938 | self.Write(70*'#') |
---|
[2449] | 1939 | #phasenam = self.Phases.keys()[0] |
---|
[3011] | 1940 | WriteCIFitem(self.fp, 'data_'+self.CIFname) |
---|
[2433] | 1941 | #print 'phasenam',phasenam |
---|
| 1942 | #phaseblk = self.Phases[phasenam] # pointer to current phase info |
---|
[2449] | 1943 | #instnam = instnam.replace(' ','') |
---|
[3011] | 1944 | #WriteCIFitem(self.fp, '_pd_block_id', |
---|
[2449] | 1945 | # str(self.CIFdate) + "|" + str(self.CIFname) + "|" + |
---|
| 1946 | # str(self.shortauthorname) + "|" + instnam + '|' + histname) |
---|
[2433] | 1947 | #WriteAudit() |
---|
| 1948 | #writeCIFtemplate(self.OverallParms['Controls'],'publ') # overall (publication) template |
---|
| 1949 | #WriteOverall() |
---|
| 1950 | #writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template |
---|
| 1951 | # report the phase info |
---|
[2449] | 1952 | #WritePhaseInfo(phasenam,hist) |
---|
[2433] | 1953 | # preferred orientation |
---|
| 1954 | #SH = FormatSH(phasenam) |
---|
| 1955 | #MD = FormatHAPpo(phasenam) |
---|
| 1956 | #if SH and MD: |
---|
[3011] | 1957 | # WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + '\n' + MD) |
---|
[2433] | 1958 | #elif SH or MD: |
---|
[3011] | 1959 | # WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + MD) |
---|
[2433] | 1960 | #else: |
---|
[3011] | 1961 | # WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', 'none') |
---|
[2433] | 1962 | # report profile, since one-block: include both histogram and phase info |
---|
[3011] | 1963 | #WriteCIFitem(self.fp, '_pd_proc_ls_profile_function', |
---|
[2433] | 1964 | # FormatInstProfile(histblk["Instrument Parameters"],histblk['hId']) |
---|
| 1965 | # +'\n'+FormatPhaseProfile(phasenam)) |
---|
[3200] | 1966 | if hist.startswith("PWDR"): |
---|
| 1967 | WritePowderData(hist) |
---|
| 1968 | elif hist.startswith("HKLF"): |
---|
| 1969 | WriteSingleXtalData(hist) |
---|
[2433] | 1970 | #writeCIFtemplate(histblk,'powder',histblk['InstrName']) # write powder template |
---|
[2867] | 1971 | #self.CloseFile() |
---|
[2433] | 1972 | return |
---|
[2867] | 1973 | #elif IncludeOnlyHist is not None: # truncate histogram list to only selected (for sequential export) |
---|
| 1974 | # self.Histograms = {IncludeOnlyHist:self.Histograms[IncludeOnlyHist]} |
---|
[3011] | 1975 | |
---|
[2449] | 1976 | #=============================================================================== |
---|
[2516] | 1977 | # the export process for a full CIF starts here |
---|
[2449] | 1978 | #=============================================================================== |
---|
[1115] | 1979 | self.InitExport(event) |
---|
[1022] | 1980 | # load all of the tree into a set of dicts |
---|
[938] | 1981 | self.loadTree() |
---|
[981] | 1982 | # create a dict with refined values and their uncertainties |
---|
| 1983 | self.loadParmDict() |
---|
[2449] | 1984 | if self.ExportSelect('ask'): return |
---|
[2897] | 1985 | if not self.filename: |
---|
| 1986 | print('No name supplied') |
---|
| 1987 | return |
---|
| 1988 | self.OpenFile() |
---|
[2449] | 1989 | #if self.ExportSelect('default'): return |
---|
[1022] | 1990 | # Someday: get restraint & constraint info |
---|
[946] | 1991 | #restraintDict = self.OverallParms.get('Restraints',{}) |
---|
[956] | 1992 | #for i in self.OverallParms['Constraints']: |
---|
| 1993 | # print i |
---|
| 1994 | # for j in self.OverallParms['Constraints'][i]: |
---|
| 1995 | # print j |
---|
[946] | 1996 | |
---|
[938] | 1997 | # is there anything to export? |
---|
[1057] | 1998 | if len(self.Phases) == len(self.powderDict) == len(self.xtalDict) == 0: |
---|
| 1999 | self.G2frame.ErrorDialog( |
---|
| 2000 | 'Empty project', |
---|
[1081] | 2001 | 'Project does not contain any data or phases. Are they interconnected?') |
---|
[1057] | 2002 | return |
---|
[2516] | 2003 | self.quickmode = False # full CIF |
---|
[1102] | 2004 | phasenam = None # include all phases |
---|
[2516] | 2005 | # Will this require a multiblock CIF? |
---|
[2449] | 2006 | if len(self.Phases) > 1: |
---|
[938] | 2007 | oneblock = False |
---|
[1010] | 2008 | elif len(self.powderDict) + len(self.xtalDict) > 1: |
---|
[938] | 2009 | oneblock = False |
---|
| 2010 | else: # one phase, one dataset, Full CIF |
---|
| 2011 | oneblock = True |
---|
| 2012 | |
---|
[1057] | 2013 | # check there is an instrument name for every histogram |
---|
[1658] | 2014 | self.ifPWDR = False |
---|
| 2015 | self.ifHKLF = False |
---|
[2449] | 2016 | invalid = 0 |
---|
| 2017 | key3 = 'InstrName' |
---|
| 2018 | for hist in self.Histograms: |
---|
| 2019 | if hist.startswith("PWDR"): |
---|
| 2020 | self.ifPWDR = True |
---|
| 2021 | key2 = "Sample Parameters" |
---|
| 2022 | d = self.Histograms[hist][key2] |
---|
| 2023 | elif hist.startswith("HKLF"): |
---|
| 2024 | self.ifHKLF = True |
---|
| 2025 | key2 = "Instrument Parameters" |
---|
[3011] | 2026 | d = self.Histograms[hist][key2][0] |
---|
[2449] | 2027 | instrname = d.get(key3) |
---|
| 2028 | if instrname is None: |
---|
| 2029 | d[key3] = '' |
---|
| 2030 | invalid += 1 |
---|
| 2031 | elif instrname.strip() == '': |
---|
| 2032 | invalid += 1 |
---|
| 2033 | if invalid: |
---|
[2867] | 2034 | #msg = "" |
---|
| 2035 | #if invalid > 3: msg = ( |
---|
| 2036 | # "\n\nNote: it may be faster to set the name for\n" |
---|
| 2037 | # "one histogram for each instrument and use the\n" |
---|
| 2038 | # "File/Copy option to duplicate the name" |
---|
| 2039 | # ) |
---|
[2449] | 2040 | if not EditInstNames(): return |
---|
[3011] | 2041 | |
---|
[2449] | 2042 | # check for a distance-angle range search range for each phase |
---|
| 2043 | for phasenam in sorted(self.Phases.keys()): |
---|
| 2044 | #i = self.Phases[phasenam]['pId'] |
---|
[3011] | 2045 | phasedict = self.Phases[phasenam] # pointer to current phase info |
---|
[2449] | 2046 | if 'DisAglCtls' not in phasedict['General']: |
---|
[3000] | 2047 | dlg = G2G.DisAglDialog( |
---|
[2449] | 2048 | self.G2frame, |
---|
| 2049 | {}, |
---|
| 2050 | phasedict['General']) |
---|
| 2051 | if dlg.ShowModal() == wx.ID_OK: |
---|
| 2052 | phasedict['General']['DisAglCtls'] = dlg.GetData() |
---|
| 2053 | else: |
---|
[1057] | 2054 | dlg.Destroy() |
---|
[2449] | 2055 | return |
---|
[1130] | 2056 | dlg.Destroy() |
---|
[2449] | 2057 | |
---|
| 2058 | # check if temperature values & pressure are defaulted |
---|
| 2059 | default = 0 |
---|
| 2060 | for hist in self.Histograms: |
---|
[3011] | 2061 | if hist.startswith("PWDR"): |
---|
[2449] | 2062 | key2 = "Sample Parameters" |
---|
| 2063 | T = self.Histograms[hist][key2].get('Temperature') |
---|
| 2064 | if not T: |
---|
| 2065 | default += 1 |
---|
| 2066 | elif T == 300: |
---|
| 2067 | default += 1 |
---|
| 2068 | P = self.Histograms[hist][key2].get('Pressure') |
---|
| 2069 | if not P: |
---|
| 2070 | default += 1 |
---|
| 2071 | elif P == 1: |
---|
| 2072 | default += 1 |
---|
| 2073 | if default > 0: |
---|
| 2074 | dlg = wx.MessageDialog( |
---|
| 2075 | self.G2frame, |
---|
| 2076 | 'Temperature/Pressure values appear to be defaulted for some powder histograms (See Sample Parameters for each PWDR tree entry). Do you want to use those values?', |
---|
| 2077 | 'Check T and P values', |
---|
| 2078 | wx.OK|wx.CANCEL) |
---|
| 2079 | ret = dlg.ShowModal() |
---|
| 2080 | dlg.Destroy() |
---|
| 2081 | if ret != wx.ID_OK: return |
---|
| 2082 | if oneblock: |
---|
[960] | 2083 | # select a dataset to use (there should only be one set in one block, |
---|
[1057] | 2084 | # but take whatever comes 1st) |
---|
[960] | 2085 | for hist in self.Histograms: |
---|
| 2086 | histblk = self.Histograms[hist] |
---|
[3011] | 2087 | if hist.startswith("PWDR"): |
---|
[960] | 2088 | instnam = histblk["Sample Parameters"]['InstrName'] |
---|
| 2089 | break # ignore all but 1st data histogram |
---|
[3011] | 2090 | elif hist.startswith("HKLF"): |
---|
[960] | 2091 | instnam = histblk["Instrument Parameters"][0]['InstrName'] |
---|
| 2092 | break # ignore all but 1st data histogram |
---|
[2516] | 2093 | # give the user a window to edit CIF contents |
---|
| 2094 | if not self.author: |
---|
| 2095 | if not EditAuthor(): return |
---|
| 2096 | self.ValidateAscii([('Author name',self.author),]) # check for ASCII strings where needed, warn on problems |
---|
[2449] | 2097 | self.cifdefs = wx.Dialog( |
---|
| 2098 | self.G2frame, |
---|
| 2099 | style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) |
---|
| 2100 | EditCIFDefaults() |
---|
| 2101 | self.cifdefs.CenterOnParent() |
---|
[2516] | 2102 | if self.cifdefs.ShowModal() != wx.ID_OK: |
---|
| 2103 | self.cifdefs.Destroy() |
---|
| 2104 | return |
---|
| 2105 | while self.ValidateAscii([('Author name',self.author), |
---|
| 2106 | ]): # validate a few things as ASCII |
---|
| 2107 | if self.cifdefs.ShowModal() != wx.ID_OK: |
---|
| 2108 | self.cifdefs.Destroy() |
---|
| 2109 | return |
---|
[2449] | 2110 | self.cifdefs.Destroy() |
---|
[938] | 2111 | #====================================================================== |
---|
| 2112 | # Start writing the CIF - single block |
---|
| 2113 | #====================================================================== |
---|
[2543] | 2114 | print('Writing CIF output to file '+self.filename+"...") |
---|
[2867] | 2115 | #self.OpenFile() |
---|
[1081] | 2116 | if self.currentExportType == 'single' or self.currentExportType == 'powder': |
---|
[1102] | 2117 | #======Data only CIF (powder/xtal) ==================================== |
---|
| 2118 | hist = self.histnam[0] |
---|
| 2119 | self.CIFname = hist[5:40].replace(' ','') |
---|
[3011] | 2120 | WriteCIFitem(self.fp, 'data_'+self.CIFname) |
---|
[1081] | 2121 | if hist.startswith("PWDR"): |
---|
| 2122 | WritePowderData(hist) |
---|
| 2123 | elif hist.startswith("HKLF"): |
---|
| 2124 | WriteSingleXtalData(hist) |
---|
| 2125 | else: |
---|
[3136] | 2126 | print ("should not happen") |
---|
[1081] | 2127 | elif oneblock: |
---|
[1102] | 2128 | #====Single block, data & phase CIF =================================== |
---|
[3011] | 2129 | WriteCIFitem(self.fp, 'data_'+self.CIFname) |
---|
| 2130 | if phasenam is None: # if not already selected, select the first phase (should be one) |
---|
[956] | 2131 | phasenam = self.Phases.keys()[0] |
---|
[938] | 2132 | #print 'phasenam',phasenam |
---|
[2433] | 2133 | #phaseblk = self.Phases[phasenam] # pointer to current phase info |
---|
[1102] | 2134 | instnam = instnam.replace(' ','') |
---|
[3011] | 2135 | WriteCIFitem(self.fp, '_pd_block_id', |
---|
[1102] | 2136 | str(self.CIFdate) + "|" + str(self.CIFname) + "|" + |
---|
| 2137 | str(self.shortauthorname) + "|" + instnam) |
---|
| 2138 | WriteAudit() |
---|
| 2139 | writeCIFtemplate(self.OverallParms['Controls'],'publ') # overall (publication) template |
---|
| 2140 | WriteOverall() |
---|
| 2141 | writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template |
---|
[956] | 2142 | # report the phase info |
---|
[938] | 2143 | WritePhaseInfo(phasenam) |
---|
[1102] | 2144 | if hist.startswith("PWDR"): |
---|
[960] | 2145 | # preferred orientation |
---|
| 2146 | SH = FormatSH(phasenam) |
---|
| 2147 | MD = FormatHAPpo(phasenam) |
---|
| 2148 | if SH and MD: |
---|
[3011] | 2149 | WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + '\n' + MD) |
---|
[960] | 2150 | elif SH or MD: |
---|
[3011] | 2151 | WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + MD) |
---|
[960] | 2152 | else: |
---|
[3011] | 2153 | WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', 'none') |
---|
[960] | 2154 | # report profile, since one-block: include both histogram and phase info |
---|
[3011] | 2155 | WriteCIFitem(self.fp, '_pd_proc_ls_profile_function', |
---|
[1013] | 2156 | FormatInstProfile(histblk["Instrument Parameters"],histblk['hId']) |
---|
| 2157 | +'\n'+FormatPhaseProfile(phasenam)) |
---|
[1074] | 2158 | histblk = self.Histograms[hist]["Sample Parameters"] |
---|
| 2159 | writeCIFtemplate(histblk,'powder',histblk['InstrName']) # write powder template |
---|
[960] | 2160 | WritePowderData(hist) |
---|
[1102] | 2161 | elif hist.startswith("HKLF"): |
---|
[1074] | 2162 | histprm = self.Histograms[hist]["Instrument Parameters"][0] |
---|
| 2163 | writeCIFtemplate(histprm,'single',histprm['InstrName']) # single crystal template |
---|
[960] | 2164 | WriteSingleXtalData(hist) |
---|
[938] | 2165 | else: |
---|
[1102] | 2166 | #=== multiblock: multiple phases and/or histograms ==================== |
---|
[1077] | 2167 | nsteps = 1 + len(self.Phases) + len(self.powderDict) + len(self.xtalDict) |
---|
[2738] | 2168 | dlg = wx.ProgressDialog('CIF progress','starting',nsteps,parent=self.G2frame) |
---|
[2527] | 2169 | # Size = dlg.GetSize() |
---|
| 2170 | # Size = (int(Size[0]*3),Size[1]) # increase size along x |
---|
| 2171 | # dlg.SetSize(Size) |
---|
[2738] | 2172 | dlg.CenterOnParent() |
---|
[1077] | 2173 | |
---|
[2738] | 2174 | # publication info |
---|
| 2175 | step = 1 |
---|
| 2176 | dlg.Update(step,"Exporting overall section") |
---|
[3011] | 2177 | WriteCIFitem(self.fp, '\ndata_'+self.CIFname+'_publ') |
---|
[2738] | 2178 | WriteAudit() |
---|
[3011] | 2179 | WriteCIFitem(self.fp, '_pd_block_id', |
---|
[2738] | 2180 | str(self.CIFdate) + "|" + str(self.CIFname) + "|" + |
---|
| 2181 | str(self.shortauthorname) + "|Overall") |
---|
| 2182 | writeCIFtemplate(self.OverallParms['Controls'],'publ') #insert the publication template |
---|
| 2183 | # ``template_publ.cif`` or a modified version |
---|
| 2184 | # overall info |
---|
[3011] | 2185 | WriteCIFitem(self.fp, 'data_'+str(self.CIFname)+'_overall') |
---|
[2738] | 2186 | WriteOverall() |
---|
| 2187 | #============================================================ |
---|
[3011] | 2188 | WriteCIFitem(self.fp, '# POINTERS TO PHASE AND HISTOGRAM BLOCKS') |
---|
[2738] | 2189 | datablockidDict = {} # save block names here -- N.B. check for conflicts between phase & hist names (unlikely!) |
---|
| 2190 | # loop over phase blocks |
---|
| 2191 | if len(self.Phases) > 1: |
---|
| 2192 | loopprefix = '' |
---|
[3011] | 2193 | WriteCIFitem(self.fp, 'loop_ _pd_phase_block_id') |
---|
[2738] | 2194 | else: |
---|
| 2195 | loopprefix = '_pd_phase_block_id' |
---|
[941] | 2196 | |
---|
[2738] | 2197 | for phasenam in sorted(self.Phases.keys()): |
---|
| 2198 | i = self.Phases[phasenam]['pId'] |
---|
| 2199 | datablockidDict[phasenam] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" + |
---|
| 2200 | 'phase_'+ str(i) + '|' + str(self.shortauthorname)) |
---|
[3011] | 2201 | WriteCIFitem(self.fp, loopprefix,datablockidDict[phasenam]) |
---|
[2738] | 2202 | # loop over data blocks |
---|
| 2203 | if len(self.powderDict) + len(self.xtalDict) > 1: |
---|
| 2204 | loopprefix = '' |
---|
[3011] | 2205 | WriteCIFitem(self.fp, 'loop_ _pd_block_diffractogram_id') |
---|
[2738] | 2206 | else: |
---|
| 2207 | loopprefix = '_pd_block_diffractogram_id' |
---|
| 2208 | for i in sorted(self.powderDict.keys()): |
---|
| 2209 | hist = self.powderDict[i] |
---|
| 2210 | histblk = self.Histograms[hist] |
---|
| 2211 | instnam = histblk["Sample Parameters"]['InstrName'] |
---|
| 2212 | instnam = instnam.replace(' ','') |
---|
| 2213 | j = histblk['hId'] |
---|
| 2214 | datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" + |
---|
| 2215 | str(self.shortauthorname) + "|" + |
---|
| 2216 | instnam + "_hist_"+str(j)) |
---|
[3011] | 2217 | WriteCIFitem(self.fp, loopprefix,datablockidDict[hist]) |
---|
[2738] | 2218 | for i in sorted(self.xtalDict.keys()): |
---|
| 2219 | hist = self.xtalDict[i] |
---|
| 2220 | histblk = self.Histograms[hist] |
---|
| 2221 | instnam = histblk["Instrument Parameters"][0]['InstrName'] |
---|
| 2222 | instnam = instnam.replace(' ','') |
---|
| 2223 | i = histblk['hId'] |
---|
| 2224 | datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" + |
---|
| 2225 | str(self.shortauthorname) + "|" + |
---|
| 2226 | instnam + "_hist_"+str(i)) |
---|
[3011] | 2227 | WriteCIFitem(self.fp, loopprefix,datablockidDict[hist]) |
---|
[2738] | 2228 | #============================================================ |
---|
| 2229 | # loop over phases, exporting them |
---|
| 2230 | phasebyhistDict = {} # create a cross-reference to phases by histogram |
---|
| 2231 | for j,phasenam in enumerate(sorted(self.Phases.keys())): |
---|
| 2232 | step += 1 |
---|
| 2233 | dlg.Update(step,"Exporting phase "+phasenam+' (#'+str(j+1)+')') |
---|
| 2234 | i = self.Phases[phasenam]['pId'] |
---|
[3011] | 2235 | WriteCIFitem(self.fp, '\ndata_'+self.CIFname+"_phase_"+str(i)) |
---|
| 2236 | WriteCIFitem(self.fp, '# Information for phase '+str(i)) |
---|
| 2237 | WriteCIFitem(self.fp, '_pd_block_id',datablockidDict[phasenam]) |
---|
[2738] | 2238 | # report the phase |
---|
| 2239 | writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template |
---|
| 2240 | WritePhaseInfo(phasenam) |
---|
| 2241 | # preferred orientation |
---|
| 2242 | if self.ifPWDR: |
---|
| 2243 | SH = FormatSH(phasenam) |
---|
| 2244 | MD = FormatHAPpo(phasenam) |
---|
| 2245 | if SH and MD: |
---|
[3011] | 2246 | WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + '\n' + MD) |
---|
[2738] | 2247 | elif SH or MD: |
---|
[3011] | 2248 | WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + MD) |
---|
[2738] | 2249 | else: |
---|
[3011] | 2250 | WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', 'none') |
---|
[2738] | 2251 | # report sample profile terms |
---|
| 2252 | PP = FormatPhaseProfile(phasenam) |
---|
| 2253 | if PP: |
---|
[3011] | 2254 | WriteCIFitem(self.fp, '_pd_proc_ls_profile_function',PP) |
---|
[2738] | 2255 | |
---|
| 2256 | #============================================================ |
---|
| 2257 | # loop over histograms, exporting them |
---|
| 2258 | for i in sorted(self.powderDict.keys()): |
---|
| 2259 | hist = self.powderDict[i] |
---|
| 2260 | histblk = self.Histograms[hist] |
---|
[3011] | 2261 | if hist.startswith("PWDR"): |
---|
[1077] | 2262 | step += 1 |
---|
[2738] | 2263 | dlg.Update(step,"Exporting "+hist.strip()) |
---|
[3011] | 2264 | WriteCIFitem(self.fp, '\ndata_'+self.CIFname+"_pwd_"+str(i)) |
---|
[2738] | 2265 | #instnam = histblk["Sample Parameters"]['InstrName'] |
---|
| 2266 | # report instrumental profile terms |
---|
[3011] | 2267 | WriteCIFitem(self.fp, '_pd_proc_ls_profile_function', |
---|
[2738] | 2268 | FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])) |
---|
[3011] | 2269 | WriteCIFitem(self.fp, '# Information for histogram '+str(i)+': '+hist) |
---|
| 2270 | WriteCIFitem(self.fp, '_pd_block_id',datablockidDict[hist]) |
---|
[2738] | 2271 | histprm = self.Histograms[hist]["Sample Parameters"] |
---|
| 2272 | writeCIFtemplate(histprm,'powder',histprm['InstrName']) # powder template |
---|
| 2273 | WritePowderData(hist) |
---|
| 2274 | for i in sorted(self.xtalDict.keys()): |
---|
| 2275 | hist = self.xtalDict[i] |
---|
| 2276 | histblk = self.Histograms[hist] |
---|
[3011] | 2277 | if hist.startswith("HKLF"): |
---|
[2738] | 2278 | step += 1 |
---|
| 2279 | dlg.Update(step,"Exporting "+hist.strip()) |
---|
[3011] | 2280 | WriteCIFitem(self.fp, '\ndata_'+self.CIFname+"_sx_"+str(i)) |
---|
[2738] | 2281 | #instnam = histblk["Instrument Parameters"][0]['InstrName'] |
---|
[3011] | 2282 | WriteCIFitem(self.fp, '# Information for histogram '+str(i)+': '+hist) |
---|
| 2283 | WriteCIFitem(self.fp, '_pd_block_id',datablockidDict[hist]) |
---|
[2738] | 2284 | histprm = self.Histograms[hist]["Instrument Parameters"][0] |
---|
| 2285 | writeCIFtemplate(histprm,'single',histprm['InstrName']) # single crystal template |
---|
| 2286 | WriteSingleXtalData(hist) |
---|
[1077] | 2287 | |
---|
[2738] | 2288 | dlg.Destroy() |
---|
[1077] | 2289 | |
---|
[3011] | 2290 | WriteCIFitem(self.fp, '#--' + 15*'eof--' + '#') |
---|
[2867] | 2291 | #self.CloseFile() |
---|
[1077] | 2292 | print("...export completed") |
---|
[2543] | 2293 | print('file '+self.fullpath) |
---|
[1077] | 2294 | # end of CIF export |
---|
[1074] | 2295 | |
---|
[2433] | 2296 | class ExportProjectCIF(ExportCIF): |
---|
| 2297 | '''Used to create a CIF of an entire project |
---|
| 2298 | |
---|
| 2299 | :param wx.Frame G2frame: reference to main GSAS-II frame |
---|
| 2300 | ''' |
---|
| 2301 | def __init__(self,G2frame): |
---|
[2449] | 2302 | ExportCIF.__init__(self, |
---|
[2433] | 2303 | G2frame=G2frame, |
---|
| 2304 | formatName = 'Full CIF', |
---|
| 2305 | extension='.cif', |
---|
| 2306 | longFormatName = 'Export project as CIF' |
---|
| 2307 | ) |
---|
| 2308 | self.exporttype = ['project'] |
---|
[3011] | 2309 | |
---|
[2433] | 2310 | def Exporter(self,event=None): |
---|
[2449] | 2311 | self._Exporter(event=event) |
---|
[2867] | 2312 | self.CloseFile() |
---|
[2433] | 2313 | |
---|
[2867] | 2314 | # def Writer(self,hist,mode='w'): |
---|
| 2315 | # '''Used for full project CIF export of a sequential fit. |
---|
| 2316 | # TODO: Needs extensive work |
---|
| 2317 | # ''' |
---|
| 2318 | # # set the project file name |
---|
| 2319 | # self.CIFname = os.path.splitext( |
---|
| 2320 | # os.path.split(self.G2frame.GSASprojectfile)[1] |
---|
| 2321 | # )[0]+'_'+hist |
---|
| 2322 | # self.CIFname = self.CIFname.replace(' ','') |
---|
| 2323 | # self.OpenFile(mode=mode) |
---|
| 2324 | # self._Exporter(IncludeOnlyHist=hist) |
---|
| 2325 | # if mode == 'w': |
---|
| 2326 | # print('CIF written to file '+self.fullpath) |
---|
| 2327 | # self.CloseFile() |
---|
[3011] | 2328 | |
---|
[1081] | 2329 | class ExportPhaseCIF(ExportCIF): |
---|
[2433] | 2330 | '''Used to create a simple CIF with one phase. Uses exact same code as |
---|
[2449] | 2331 | :class:`ExportCIF` except that `phaseOnly` is set for the Exporter |
---|
[1115] | 2332 | Shows up in menu as Quick CIF. |
---|
[1077] | 2333 | |
---|
| 2334 | :param wx.Frame G2frame: reference to main GSAS-II frame |
---|
| 2335 | ''' |
---|
| 2336 | def __init__(self,G2frame): |
---|
[2449] | 2337 | ExportCIF.__init__(self, |
---|
[1077] | 2338 | G2frame=G2frame, |
---|
[1081] | 2339 | formatName = 'Quick CIF', |
---|
[1077] | 2340 | extension='.cif', |
---|
[1081] | 2341 | longFormatName = 'Export one phase in CIF' |
---|
[1077] | 2342 | ) |
---|
[1081] | 2343 | self.exporttype = ['phase'] |
---|
| 2344 | # CIF-specific items |
---|
[1077] | 2345 | self.author = '' |
---|
| 2346 | |
---|
[2433] | 2347 | def Exporter(self,event=None): |
---|
[2449] | 2348 | # get a phase and file name |
---|
| 2349 | # the export process starts here |
---|
| 2350 | self.InitExport(event) |
---|
| 2351 | # load all of the tree into a set of dicts |
---|
| 2352 | self.loadTree() |
---|
| 2353 | # create a dict with refined values and their uncertainties |
---|
| 2354 | self.loadParmDict() |
---|
| 2355 | self.multiple = False |
---|
| 2356 | self.currentExportType = 'phase' |
---|
| 2357 | if self.ExportSelect('ask'): return |
---|
[2867] | 2358 | self.OpenFile() |
---|
[2449] | 2359 | self._Exporter(event=event,phaseOnly=self.phasenam[0]) |
---|
[2867] | 2360 | self.CloseFile() |
---|
[2433] | 2361 | |
---|
| 2362 | def Writer(self,hist,phasenam,mode='w'): |
---|
| 2363 | # set the project file name |
---|
| 2364 | self.CIFname = os.path.splitext( |
---|
| 2365 | os.path.split(self.G2frame.GSASprojectfile)[1] |
---|
| 2366 | )[0]+'_'+phasenam+'_'+hist |
---|
| 2367 | self.CIFname = self.CIFname.replace(' ','') |
---|
| 2368 | self.OpenFile(mode=mode) |
---|
| 2369 | self._Exporter(phaseOnly=phasenam) |
---|
| 2370 | self.CloseFile() |
---|
| 2371 | |
---|
[2449] | 2372 | class ExportPwdrCIF(ExportCIF): |
---|
[1081] | 2373 | '''Used to create a simple CIF containing diffraction data only. Uses exact same code as |
---|
[2449] | 2374 | :class:`ExportCIF` except that `histOnly` is set for the Exporter |
---|
| 2375 | Shows up in menu as Quick CIF. |
---|
[1081] | 2376 | |
---|
| 2377 | :param wx.Frame G2frame: reference to main GSAS-II frame |
---|
| 2378 | ''' |
---|
| 2379 | def __init__(self,G2frame): |
---|
[2449] | 2380 | ExportCIF.__init__(self, |
---|
[1081] | 2381 | G2frame=G2frame, |
---|
| 2382 | formatName = 'Data-only CIF', |
---|
| 2383 | extension='.cif', |
---|
| 2384 | longFormatName = 'Export data as CIF' |
---|
| 2385 | ) |
---|
[3216] | 2386 | if G2frame is None: raise AttributeError('CIF export requires data tree') # prevent use from Scriptable |
---|
[2449] | 2387 | self.exporttype = ['powder'] |
---|
[1081] | 2388 | # CIF-specific items |
---|
| 2389 | self.author = '' |
---|
| 2390 | |
---|
[2433] | 2391 | def Exporter(self,event=None): |
---|
[2449] | 2392 | self.InitExport(event) |
---|
| 2393 | # load all of the tree into a set of dicts |
---|
| 2394 | self.currentExportType = None |
---|
| 2395 | self.loadTree() |
---|
| 2396 | self.currentExportType = 'powder' |
---|
| 2397 | # create a dict with refined values and their uncertainties |
---|
| 2398 | self.loadParmDict() |
---|
| 2399 | self.multiple = False |
---|
| 2400 | if self.ExportSelect( # set export parameters |
---|
| 2401 | AskFile='ask' # get a file name/directory to save in |
---|
| 2402 | ): return |
---|
[3200] | 2403 | self.OpenFile() |
---|
[2449] | 2404 | self._Exporter(event=event,histOnly=self.histnam[0]) |
---|
| 2405 | |
---|
[2867] | 2406 | def Writer(self,hist,mode='w'): |
---|
| 2407 | '''Used for histogram CIF export of a sequential fit. |
---|
| 2408 | ''' |
---|
| 2409 | # set the project file name |
---|
| 2410 | self.CIFname = os.path.splitext( |
---|
| 2411 | os.path.split(self.G2frame.GSASprojectfile)[1] |
---|
| 2412 | )[0]+'_'+hist |
---|
| 2413 | self.CIFname = self.CIFname.replace(' ','') |
---|
| 2414 | self.OpenFile(mode=mode) |
---|
| 2415 | self._Exporter(histOnly=hist) |
---|
| 2416 | if mode == 'w': |
---|
| 2417 | print('CIF written to file '+self.fullpath) |
---|
| 2418 | self.CloseFile() |
---|
[3011] | 2419 | |
---|
[2449] | 2420 | class ExportHKLCIF(ExportCIF): |
---|
| 2421 | '''Used to create a simple CIF containing diffraction data only. Uses exact same code as |
---|
| 2422 | :class:`ExportCIF` except that `histOnly` is set for the Exporter |
---|
| 2423 | Shows up in menu as Quick CIF. |
---|
| 2424 | |
---|
| 2425 | :param wx.Frame G2frame: reference to main GSAS-II frame |
---|
| 2426 | ''' |
---|
| 2427 | def __init__(self,G2frame): |
---|
| 2428 | ExportCIF.__init__(self, |
---|
| 2429 | G2frame=G2frame, |
---|
| 2430 | formatName = 'Data-only CIF', |
---|
| 2431 | extension='.cif', |
---|
| 2432 | longFormatName = 'Export data as CIF' |
---|
| 2433 | ) |
---|
| 2434 | self.exporttype = ['single'] |
---|
| 2435 | # CIF-specific items |
---|
| 2436 | self.author = '' |
---|
| 2437 | |
---|
| 2438 | def Exporter(self,event=None): |
---|
| 2439 | self.InitExport(event) |
---|
| 2440 | # load all of the tree into a set of dicts |
---|
| 2441 | self.currentExportType = None |
---|
| 2442 | self.loadTree() |
---|
| 2443 | self.currentExportType = 'single' |
---|
| 2444 | # create a dict with refined values and their uncertainties |
---|
| 2445 | self.loadParmDict() |
---|
| 2446 | self.multiple = False |
---|
| 2447 | if self.ExportSelect( # set export parameters |
---|
| 2448 | AskFile='ask' # get a file name/directory to save in |
---|
| 2449 | ): return |
---|
[3200] | 2450 | self.OpenFile() |
---|
[2449] | 2451 | self._Exporter(event=event,histOnly=self.histnam[0]) |
---|
[3011] | 2452 | |
---|
[1074] | 2453 | #=============================================================================== |
---|
| 2454 | # misc CIF utilities |
---|
| 2455 | #=============================================================================== |
---|
| 2456 | def PickleCIFdict(fil): |
---|
| 2457 | '''Loads a CIF dictionary, cherry picks out the items needed |
---|
| 2458 | by local code and sticks them into a python dict and writes |
---|
[3136] | 2459 | that dict out as a pickle file for later reuse. |
---|
[1074] | 2460 | If the write fails a warning message is printed, |
---|
| 2461 | but no exception occurs. |
---|
| 2462 | |
---|
| 2463 | :param str fil: file name of CIF dictionary, will usually end |
---|
| 2464 | in .dic |
---|
[3011] | 2465 | :returns: the dict with the definitions |
---|
[1074] | 2466 | ''' |
---|
| 2467 | import CifFile as cif # PyCifRW from James Hester |
---|
| 2468 | cifdic = {} |
---|
| 2469 | try: |
---|
| 2470 | fp = open(fil,'r') # patch: open file to avoid windows bug |
---|
| 2471 | dictobj = cif.CifDic(fp) |
---|
| 2472 | fp.close() |
---|
| 2473 | except IOError: |
---|
| 2474 | dictobj = cif.CifDic(fil) |
---|
[2819] | 2475 | if DEBUG: print('loaded '+fil) |
---|
[1074] | 2476 | for item in dictobj.keys(): |
---|
| 2477 | cifdic[item] = {} |
---|
| 2478 | for j in ( |
---|
| 2479 | '_definition','_type', |
---|
| 2480 | '_enumeration', |
---|
| 2481 | '_enumeration_detail', |
---|
| 2482 | '_enumeration_range'): |
---|
| 2483 | if dictobj[item].get(j): |
---|
| 2484 | cifdic[item][j] = dictobj[item][j] |
---|
| 2485 | try: |
---|
| 2486 | fil = os.path.splitext(fil)[0]+'.cpickle' |
---|
| 2487 | fp = open(fil,'w') |
---|
[3136] | 2488 | pickle.dump(cifdic,fp) |
---|
[1074] | 2489 | fp.close() |
---|
[2819] | 2490 | if DEBUG: print('wrote '+fil) |
---|
[1074] | 2491 | except: |
---|
[2819] | 2492 | print ('Unable to write '+fil) |
---|
[1074] | 2493 | return cifdic |
---|
| 2494 | |
---|
| 2495 | def LoadCIFdic(): |
---|
| 2496 | '''Create a composite core+powder CIF lookup dict containing |
---|
| 2497 | information about all items in the CIF dictionaries, loading |
---|
| 2498 | pickled files if possible. The routine looks for files |
---|
| 2499 | named cif_core.cpickle and cif_pd.cpickle in every |
---|
| 2500 | directory in the path and if they are not found, files |
---|
| 2501 | cif_core.dic and/or cif_pd.dic are read. |
---|
| 2502 | |
---|
[3011] | 2503 | :returns: the dict with the definitions |
---|
[1074] | 2504 | ''' |
---|
| 2505 | cifdic = {} |
---|
| 2506 | for ftyp in "cif_core","cif_pd": |
---|
| 2507 | for loc in sys.path: |
---|
| 2508 | fil = os.path.join(loc,ftyp+".cpickle") |
---|
| 2509 | if not os.path.exists(fil): continue |
---|
| 2510 | fp = open(fil,'r') |
---|
| 2511 | try: |
---|
[3136] | 2512 | cifdic.update(pickle.load(fp)) |
---|
[2819] | 2513 | if DEBUG: print('reloaded '+fil) |
---|
[1074] | 2514 | break |
---|
| 2515 | finally: |
---|
| 2516 | fp.close() |
---|
| 2517 | else: |
---|
| 2518 | for loc in sys.path: |
---|
| 2519 | fil = os.path.join(loc,ftyp+".dic") |
---|
| 2520 | if not os.path.exists(fil): continue |
---|
| 2521 | #try: |
---|
| 2522 | if True: |
---|
| 2523 | cifdic.update(PickleCIFdict(fil)) |
---|
| 2524 | break |
---|
| 2525 | #except: |
---|
| 2526 | # pass |
---|
| 2527 | else: |
---|
| 2528 | print('Could not load '+ftyp+' dictionary') |
---|
| 2529 | return cifdic |
---|
| 2530 | |
---|
| 2531 | class CIFdefHelp(wx.Button): |
---|
| 2532 | '''Create a help button that displays help information on |
---|
| 2533 | the current data item |
---|
| 2534 | |
---|
| 2535 | :param parent: the panel which will be the parent of the button |
---|
| 2536 | :param str msg: the help text to be displayed |
---|
| 2537 | :param wx.Dialog helpwin: Frame for CIF editing dialog |
---|
| 2538 | :param wx.TextCtrl helptxt: TextCtrl where help text is placed |
---|
| 2539 | ''' |
---|
| 2540 | def __init__(self,parent,msg,helpwin,helptxt): |
---|
| 2541 | wx.Button.__init__(self,parent,wx.ID_HELP) |
---|
| 2542 | self.Bind(wx.EVT_BUTTON,self._onPress) |
---|
| 2543 | self.msg=msg |
---|
| 2544 | self.parent = parent |
---|
| 2545 | #self.helpwin = self.parent.helpwin |
---|
| 2546 | self.helpwin = helpwin |
---|
| 2547 | self.helptxt = helptxt |
---|
| 2548 | def _onPress(self,event): |
---|
| 2549 | 'Respond to a button press by displaying the requested text' |
---|
| 2550 | try: |
---|
| 2551 | #helptxt = self.helptxt |
---|
| 2552 | ow,oh = self.helptxt.GetSize() |
---|
| 2553 | self.helptxt.SetLabel(self.msg) |
---|
| 2554 | w,h = self.helptxt.GetSize() |
---|
| 2555 | if h > oh: |
---|
| 2556 | self.helpwin.GetSizer().Fit(self.helpwin) |
---|
| 2557 | except: # error posting help, ignore |
---|
| 2558 | return |
---|
| 2559 | |
---|
| 2560 | def CIF2dict(cf): |
---|
| 2561 | '''copy the contents of a CIF out from a PyCifRW block object |
---|
| 2562 | into a dict |
---|
| 2563 | |
---|
| 2564 | :returns: cifblk, loopstructure where cifblk is a dict with |
---|
| 2565 | CIF items and loopstructure is a list of lists that defines |
---|
[3011] | 2566 | which items are in which loops. |
---|
[1074] | 2567 | ''' |
---|
| 2568 | blk = cf.keys()[0] # assume templates are a single CIF block, use the 1st |
---|
| 2569 | loopstructure = cf[blk].loopnames()[:] # copy over the list of loop contents |
---|
| 2570 | dblk = {} |
---|
| 2571 | for item in cf[blk].keys(): # make a copy of all the items in the block |
---|
| 2572 | dblk[item] = cf[blk][item] |
---|
| 2573 | return dblk,loopstructure |
---|
| 2574 | |
---|
| 2575 | def dict2CIF(dblk,loopstructure,blockname='Template'): |
---|
| 2576 | '''Create a PyCifRW CIF object containing a single CIF |
---|
| 2577 | block object from a dict and loop structure list. |
---|
| 2578 | |
---|
| 2579 | :param dblk: a dict containing values for each CIF item |
---|
| 2580 | :param list loopstructure: a list of lists containing the contents of |
---|
| 2581 | each loop, as an example:: |
---|
| 2582 | |
---|
| 2583 | [ ["_a","_b"], ["_c"], ["_d_1","_d_2","_d_3"]] |
---|
| 2584 | |
---|
| 2585 | this describes a CIF with this type of structure:: |
---|
| 2586 | |
---|
| 2587 | loop_ _a _b <a1> <b1> <a2> ... |
---|
| 2588 | loop_ _c <c1> <c2>... |
---|
| 2589 | loop _d_1 _d_2 _d_3 ... |
---|
| 2590 | |
---|
| 2591 | Note that the values for each looped CIF item, such as _a, |
---|
| 2592 | are contained in a list, for example as cifblk["_a"] |
---|
| 2593 | |
---|
| 2594 | :param str blockname: an optional name for the CIF block. |
---|
| 2595 | Defaults to 'Template' |
---|
| 2596 | |
---|
[3011] | 2597 | :returns: the newly created PyCifRW CIF object |
---|
[1074] | 2598 | ''' |
---|
| 2599 | |
---|
| 2600 | import CifFile as cif # PyCifRW from James Hester |
---|
| 2601 | # compile a 'list' of items in loops |
---|
| 2602 | loopnames = set() |
---|
| 2603 | for i in loopstructure: |
---|
| 2604 | loopnames |= set(i) |
---|
| 2605 | # create a new block |
---|
| 2606 | newblk = cif.CifBlock() |
---|
| 2607 | # add the looped items |
---|
| 2608 | for keys in loopstructure: |
---|
| 2609 | vals = [] |
---|
| 2610 | for key in keys: |
---|
| 2611 | vals.append(dblk[key]) |
---|
| 2612 | newblk.AddCifItem(([keys],[vals])) |
---|
| 2613 | # add the non-looped items |
---|
| 2614 | for item in dblk: |
---|
| 2615 | if item in loopnames: continue |
---|
| 2616 | newblk[item] = dblk[item] |
---|
| 2617 | # create a CIF and add the block |
---|
| 2618 | newcf = cif.CifFile() |
---|
[3011] | 2619 | newcf[blockname] = newblk |
---|
[1074] | 2620 | return newcf |
---|
| 2621 | |
---|
| 2622 | |
---|
| 2623 | class EditCIFtemplate(wx.Dialog): |
---|
| 2624 | '''Create a dialog for editing a CIF template. The edited information is |
---|
| 2625 | placed in cifblk. If the CIF is saved as a file, the name of that file |
---|
| 2626 | is saved as ``self.newfile``. |
---|
[3011] | 2627 | |
---|
[1074] | 2628 | :param wx.Frame parent: parent frame or None |
---|
| 2629 | :param cifblk: dict or PyCifRW block containing values for each CIF item |
---|
| 2630 | :param list loopstructure: a list of lists containing the contents of |
---|
| 2631 | each loop, as an example:: |
---|
| 2632 | |
---|
| 2633 | [ ["_a","_b"], ["_c"], ["_d_1","_d_2","_d_3"]] |
---|
| 2634 | |
---|
| 2635 | this describes a CIF with this type of structure:: |
---|
| 2636 | |
---|
| 2637 | loop_ _a _b <a1> <b1> <a2> ... |
---|
| 2638 | loop_ _c <c1> <c2>... |
---|
| 2639 | loop _d_1 _d_2 _d_3 ... |
---|
| 2640 | |
---|
| 2641 | Note that the values for each looped CIF item, such as _a, |
---|
| 2642 | are contained in a list, for example as cifblk["_a"] |
---|
[3011] | 2643 | |
---|
| 2644 | :param str defaultname: specifies the default file name to be used for |
---|
[1074] | 2645 | saving the CIF. |
---|
| 2646 | ''' |
---|
| 2647 | def __init__(self,parent,cifblk,loopstructure,defaultname): |
---|
| 2648 | OKbuttons = [] |
---|
| 2649 | self.cifblk = cifblk |
---|
| 2650 | self.loopstructure = loopstructure |
---|
| 2651 | self.newfile = None |
---|
[3011] | 2652 | self.defaultname = defaultname |
---|
[1074] | 2653 | global CIFdic # once this is loaded, keep it around |
---|
| 2654 | if CIFdic is None: |
---|
| 2655 | CIFdic = LoadCIFdic() |
---|
| 2656 | wx.Dialog.__init__(self,parent,style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) |
---|
| 2657 | |
---|
| 2658 | # define widgets that will be needed during panel creation |
---|
| 2659 | self.helptxt = wx.StaticText(self,wx.ID_ANY,"") |
---|
| 2660 | savebtn = wx.Button(self, wx.ID_CLOSE, "Save as template") |
---|
| 2661 | OKbuttons.append(savebtn) |
---|
| 2662 | savebtn.Bind(wx.EVT_BUTTON,self._onSave) |
---|
| 2663 | OKbtn = wx.Button(self, wx.ID_OK, "Use") |
---|
| 2664 | OKbtn.SetDefault() |
---|
| 2665 | OKbuttons.append(OKbtn) |
---|
| 2666 | |
---|
| 2667 | self.SetTitle('Edit items in CIF template') |
---|
| 2668 | vbox = wx.BoxSizer(wx.VERTICAL) |
---|
| 2669 | cpnl = EditCIFpanel(self,cifblk,loopstructure,CIFdic,OKbuttons,size=(300,300)) |
---|
| 2670 | vbox.Add(cpnl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 0) |
---|
[1831] | 2671 | G2G.HorizontalLine(vbox,self) |
---|
[1074] | 2672 | vbox.Add(self.helptxt, 0, wx.EXPAND|wx.ALL, 5) |
---|
[1831] | 2673 | G2G.HorizontalLine(vbox,self) |
---|
[1074] | 2674 | btnsizer = wx.BoxSizer(wx.HORIZONTAL) |
---|
| 2675 | btn = wx.Button(self, wx.ID_CANCEL) |
---|
| 2676 | btnsizer.Add(btn,0,wx.ALIGN_CENTER|wx.ALL) |
---|
| 2677 | btnsizer.Add(savebtn,0,wx.ALIGN_CENTER|wx.ALL) |
---|
| 2678 | btnsizer.Add(OKbtn,0,wx.ALIGN_CENTER|wx.ALL) |
---|
| 2679 | vbox.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5) |
---|
| 2680 | self.SetSizer(vbox) |
---|
| 2681 | vbox.Fit(self) |
---|
| 2682 | def Post(self): |
---|
| 2683 | '''Display the dialog |
---|
[3011] | 2684 | |
---|
[1074] | 2685 | :returns: True unless Cancel has been pressed. |
---|
| 2686 | ''' |
---|
| 2687 | return (self.ShowModal() == wx.ID_OK) |
---|
| 2688 | def _onSave(self,event): |
---|
| 2689 | 'Save CIF entries in a template file' |
---|
[2109] | 2690 | pth = G2G.GetExportPath(self.G2frame) |
---|
[1074] | 2691 | dlg = wx.FileDialog( |
---|
| 2692 | self, message="Save as CIF template", |
---|
[2109] | 2693 | defaultDir=pth, |
---|
[1074] | 2694 | defaultFile=self.defaultname, |
---|
| 2695 | wildcard="CIF (*.cif)|*.cif", |
---|
[2109] | 2696 | style=wx.SAVE) |
---|
[1074] | 2697 | val = (dlg.ShowModal() == wx.ID_OK) |
---|
| 2698 | fil = dlg.GetPath() |
---|
| 2699 | dlg.Destroy() |
---|
| 2700 | if val: # ignore a Cancel button |
---|
| 2701 | fil = os.path.splitext(fil)[0]+'.cif' # force extension |
---|
| 2702 | fp = open(fil,'w') |
---|
| 2703 | newcf = dict2CIF(self.cifblk,self.loopstructure) |
---|
| 2704 | fp.write(newcf.WriteOut()) |
---|
| 2705 | fp.close() |
---|
| 2706 | self.newfile = fil |
---|
| 2707 | self.EndModal(wx.ID_OK) |
---|
| 2708 | |
---|
| 2709 | class EditCIFpanel(wxscroll.ScrolledPanel): |
---|
| 2710 | '''Creates a scrolled panel for editing CIF template items |
---|
| 2711 | |
---|
| 2712 | :param wx.Frame parent: parent frame where panel will be placed |
---|
| 2713 | :param cifblk: dict or PyCifRW block containing values for each CIF item |
---|
| 2714 | :param list loopstructure: a list of lists containing the contents of |
---|
| 2715 | each loop, as an example:: |
---|
| 2716 | |
---|
| 2717 | [ ["_a","_b"], ["_c"], ["_d_1","_d_2","_d_3"]] |
---|
| 2718 | |
---|
| 2719 | this describes a CIF with this type of structure:: |
---|
| 2720 | |
---|
| 2721 | loop_ _a _b <a1> <b1> <a2> ... |
---|
| 2722 | loop_ _c <c1> <c2>... |
---|
| 2723 | loop _d_1 _d_2 _d_3 ... |
---|
| 2724 | |
---|
| 2725 | Note that the values for each looped CIF item, such as _a, |
---|
| 2726 | are contained in a list, for example as cifblk["_a"] |
---|
| 2727 | |
---|
| 2728 | :param dict cifdic: optional CIF dictionary definitions |
---|
| 2729 | :param list OKbuttons: A list of wx.Button objects that should |
---|
| 2730 | be disabled when information in the CIF is invalid |
---|
| 2731 | :param (other): optional keyword parameters for wx.ScrolledPanel |
---|
| 2732 | ''' |
---|
| 2733 | def __init__(self, parent, cifblk, loopstructure, cifdic={}, OKbuttons=[], **kw): |
---|
| 2734 | self.parent = parent |
---|
| 2735 | wxscroll.ScrolledPanel.__init__(self, parent, wx.ID_ANY, **kw) |
---|
| 2736 | self.vbox = None |
---|
| 2737 | self.AddDict = None |
---|
| 2738 | self.cifdic = cifdic |
---|
| 2739 | self.cifblk = cifblk |
---|
| 2740 | self.loops = loopstructure |
---|
| 2741 | self.parent = parent |
---|
| 2742 | self.LayoutCalled = False |
---|
| 2743 | self.parentOKbuttons = OKbuttons |
---|
| 2744 | self.ValidatedControlsList = [] |
---|
| 2745 | self._fill() |
---|
| 2746 | def _fill(self): |
---|
| 2747 | 'Fill the scrolled panel with widgets for each CIF item' |
---|
| 2748 | wx.BeginBusyCursor() |
---|
| 2749 | self.AddDict = {} |
---|
| 2750 | self.ValidatedControlsList = [] |
---|
| 2751 | # delete any only contents |
---|
| 2752 | if self.vbox: |
---|
[3136] | 2753 | if 'phoenix' in wx.version(): |
---|
| 2754 | self.vbox.Clear(True) |
---|
| 2755 | else: |
---|
| 2756 | self.vbox.DeleteWindows() |
---|
[1074] | 2757 | self.vbox = None |
---|
| 2758 | self.Update() |
---|
| 2759 | vbox = wx.BoxSizer(wx.VERTICAL) |
---|
| 2760 | self.vbox = vbox |
---|
| 2761 | # compile a 'list' of items in loops |
---|
| 2762 | loopnames = set() |
---|
| 2763 | for i in self.loops: |
---|
| 2764 | loopnames |= set(i) |
---|
| 2765 | # post the looped CIF items |
---|
| 2766 | for lnum,lp in enumerate(self.loops): |
---|
| 2767 | hbox = wx.BoxSizer(wx.HORIZONTAL) |
---|
| 2768 | hbox.Add(wx.StaticText(self,wx.ID_ANY,'Loop '+str(lnum+1))) |
---|
| 2769 | vbox.Add(hbox) |
---|
| 2770 | but = wx.Button(self,wx.ID_ANY,"Add row") |
---|
| 2771 | self.AddDict[but]=lnum |
---|
[3011] | 2772 | |
---|
| 2773 | hbox.Add(but) |
---|
[1074] | 2774 | but.Bind(wx.EVT_BUTTON,self.OnAddRow) |
---|
| 2775 | fbox = wx.GridBagSizer(0, 0) |
---|
| 2776 | vbox.Add(fbox) |
---|
| 2777 | rows = 0 |
---|
| 2778 | for i,item in enumerate(lp): |
---|
| 2779 | txt = wx.StaticText(self,wx.ID_ANY,item+" ") |
---|
| 2780 | fbox.Add(txt,(0,i+1)) |
---|
| 2781 | # if self.cifdic.get(item): |
---|
| 2782 | # df = self.cifdic[item].get('_definition') |
---|
| 2783 | # if df: |
---|
| 2784 | # txt.SetToolTipString(G2IO.trim(df)) |
---|
| 2785 | # but = CIFdefHelp(self, |
---|
| 2786 | # "Definition for "+item+":\n\n"+G2IO.trim(df), |
---|
| 2787 | # self.parent, |
---|
| 2788 | # self.parent.helptxt) |
---|
| 2789 | # fbox.Add(but,(1,i+1),flag=wx.ALIGN_CENTER) |
---|
| 2790 | for j,val in enumerate(self.cifblk[item]): |
---|
| 2791 | ent = self.CIFEntryWidget(self.cifblk[item],j,item) |
---|
| 2792 | #fbox.Add(ent,(j+2,i+1),flag=wx.EXPAND|wx.ALL) |
---|
| 2793 | fbox.Add(ent,(j+1,i+1),flag=wx.EXPAND|wx.ALL) |
---|
| 2794 | if self.cifdic.get(item): |
---|
| 2795 | df = self.cifdic[item].get('_definition') |
---|
| 2796 | if df: |
---|
| 2797 | txt.SetToolTipString(G2IO.trim(df)) |
---|
| 2798 | but = CIFdefHelp(self, |
---|
| 2799 | "Definition for "+item+":\n\n"+G2IO.trim(df), |
---|
| 2800 | self.parent, |
---|
| 2801 | self.parent.helptxt) |
---|
| 2802 | fbox.Add(but,(j+2,i+1),flag=wx.ALIGN_CENTER) |
---|
| 2803 | rows = max(rows,len(self.cifblk[item])) |
---|
| 2804 | for i in range(rows): |
---|
| 2805 | txt = wx.StaticText(self,wx.ID_ANY,str(i+1)) |
---|
| 2806 | fbox.Add(txt,(i+2,0)) |
---|
| 2807 | line = wx.StaticLine(self,wx.ID_ANY, size=(-1,3), style=wx.LI_HORIZONTAL) |
---|
| 2808 | vbox.Add(line, 0, wx.EXPAND|wx.ALIGN_CENTER|wx.ALL, 10) |
---|
[3011] | 2809 | |
---|
[1074] | 2810 | # post the non-looped CIF items |
---|
| 2811 | for item in sorted(self.cifblk.keys()): |
---|
| 2812 | if item not in loopnames: |
---|
| 2813 | hbox = wx.BoxSizer(wx.HORIZONTAL) |
---|
| 2814 | vbox.Add(hbox) |
---|
| 2815 | txt = wx.StaticText(self,wx.ID_ANY,item) |
---|
| 2816 | hbox.Add(txt) |
---|
| 2817 | ent = self.CIFEntryWidget(self.cifblk,item,item) |
---|
| 2818 | hbox.Add(ent) |
---|
| 2819 | if self.cifdic.get(item): |
---|
| 2820 | df = self.cifdic[item].get('_definition') |
---|
| 2821 | if df: |
---|
| 2822 | txt.SetToolTipString(G2IO.trim(df)) |
---|
| 2823 | but = CIFdefHelp(self, |
---|
| 2824 | "Definition for "+item+":\n\n"+G2IO.trim(df), |
---|
| 2825 | self.parent, |
---|
| 2826 | self.parent.helptxt) |
---|
| 2827 | hbox.Add(but,0,wx.ALL,2) |
---|
| 2828 | self.SetSizer(vbox) |
---|
| 2829 | #vbox.Fit(self.parent) |
---|
| 2830 | self.SetAutoLayout(1) |
---|
| 2831 | self.SetupScrolling() |
---|
| 2832 | self.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded) |
---|
| 2833 | self.Layout() |
---|
| 2834 | wx.EndBusyCursor() |
---|
| 2835 | def OnLayoutNeeded(self,event): |
---|
| 2836 | '''Called when an update of the panel layout is needed. Calls |
---|
| 2837 | self.DoLayout after the current operations are complete using |
---|
| 2838 | CallAfter. This is called only once, according to flag |
---|
[3011] | 2839 | self.LayoutCalled, which is cleared in self.DoLayout. |
---|
[1074] | 2840 | ''' |
---|
| 2841 | if self.LayoutCalled: return # call already queued |
---|
| 2842 | wx.CallAfter(self.DoLayout) # queue a call |
---|
| 2843 | self.LayoutCalled = True |
---|
| 2844 | def DoLayout(self): |
---|
| 2845 | '''Update the Layout and scroll bars for the Panel. Clears |
---|
| 2846 | self.LayoutCalled so that next change to panel can |
---|
| 2847 | request a new update |
---|
| 2848 | ''' |
---|
| 2849 | wx.BeginBusyCursor() |
---|
| 2850 | self.Layout() |
---|
| 2851 | self.SetupScrolling() |
---|
| 2852 | wx.EndBusyCursor() |
---|
| 2853 | self.LayoutCalled = False |
---|
| 2854 | def OnAddRow(self,event): |
---|
| 2855 | 'add a row to a loop' |
---|
| 2856 | lnum = self.AddDict.get(event.GetEventObject()) |
---|
| 2857 | if lnum is None: return |
---|
| 2858 | for item in self.loops[lnum]: |
---|
| 2859 | self.cifblk[item].append('?') |
---|
| 2860 | self._fill() |
---|
| 2861 | |
---|
| 2862 | def ControlOKButton(self,setvalue): |
---|
| 2863 | '''Enable or Disable the OK button(s) for the dialog. Note that this is |
---|
| 2864 | passed into the ValidatedTxtCtrl for use by validators. |
---|
| 2865 | |
---|
| 2866 | :param bool setvalue: if True, all entries in the dialog are |
---|
| 2867 | checked for validity. The first invalid control triggers |
---|
| 2868 | disabling of buttons. |
---|
| 2869 | If False then the OK button(s) are disabled with no checking |
---|
| 2870 | of the invalid flag for each control. |
---|
| 2871 | ''' |
---|
| 2872 | if setvalue: # turn button on, do only if all controls show as valid |
---|
| 2873 | for ctrl in self.ValidatedControlsList: |
---|
| 2874 | if ctrl.invalid: |
---|
| 2875 | for btn in self.parentOKbuttons: |
---|
| 2876 | btn.Disable() |
---|
| 2877 | return |
---|
| 2878 | else: |
---|
| 2879 | for btn in self.parentOKbuttons: |
---|
| 2880 | btn.Enable() |
---|
| 2881 | else: |
---|
| 2882 | for btn in self.parentOKbuttons: |
---|
| 2883 | btn.Disable() |
---|
[3011] | 2884 | |
---|
[1074] | 2885 | def CIFEntryWidget(self,dct,item,dataname): |
---|
| 2886 | '''Create an entry widget for a CIF item. Use a validated entry for numb values |
---|
| 2887 | where int is required when limits are integers and floats otherwise. |
---|
| 2888 | At present this does not allow entry of the special CIF values of "." and "?" for |
---|
| 2889 | numerical values and highlights them as invalid. |
---|
[3011] | 2890 | Use a selection widget when there are specific enumerated values for a string. |
---|
[1074] | 2891 | ''' |
---|
| 2892 | if self.cifdic.get(dataname): |
---|
| 2893 | if self.cifdic[dataname].get('_enumeration'): |
---|
| 2894 | values = ['?']+self.cifdic[dataname]['_enumeration'] |
---|
| 2895 | choices = ['undefined'] |
---|
| 2896 | for i in self.cifdic[dataname].get('_enumeration_detail',values): |
---|
| 2897 | choices.append(G2IO.trim(i)) |
---|
[1831] | 2898 | ent = G2G.EnumSelector(self, dct, item, choices, values, size=(200, -1)) |
---|
[1074] | 2899 | return ent |
---|
| 2900 | if self.cifdic[dataname].get('_type') == 'numb': |
---|
| 2901 | mn = None |
---|
| 2902 | mx = None |
---|
| 2903 | hint = int |
---|
| 2904 | if self.cifdic[dataname].get('_enumeration_range'): |
---|
| 2905 | rng = self.cifdic[dataname]['_enumeration_range'].split(':') |
---|
| 2906 | if '.' in rng[0] or '.' in rng[1]: hint = float |
---|
| 2907 | if rng[0]: mn = hint(rng[0]) |
---|
| 2908 | if rng[1]: mx = hint(rng[1]) |
---|
[2516] | 2909 | ent = G2G.ValidatedTxtCtrl( |
---|
[1074] | 2910 | self,dct,item,typeHint=hint,min=mn,max=mx, |
---|
[2516] | 2911 | CIFinput=True,ASCIIonly=True, |
---|
[1074] | 2912 | OKcontrol=self.ControlOKButton) |
---|
| 2913 | self.ValidatedControlsList.append(ent) |
---|
| 2914 | return ent |
---|
| 2915 | rw1 = rw.ResizeWidget(self) |
---|
[2516] | 2916 | ent = G2G.ValidatedTxtCtrl( |
---|
[1074] | 2917 | rw1,dct,item,size=(100, 20), |
---|
| 2918 | style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER, |
---|
[2516] | 2919 | CIFinput=True,ASCIIonly=True, |
---|
[1074] | 2920 | OKcontrol=self.ControlOKButton) |
---|
| 2921 | self.ValidatedControlsList.append(ent) |
---|
| 2922 | return rw1 |
---|
| 2923 | |
---|
| 2924 | class CIFtemplateSelect(wx.BoxSizer): |
---|
| 2925 | '''Create a set of buttons to show, select and edit a CIF template |
---|
[3011] | 2926 | |
---|
[1074] | 2927 | :param frame: wx.Frame object of parent |
---|
| 2928 | :param panel: wx.Panel object where widgets should be placed |
---|
| 2929 | :param str tmplate: one of 'publ', 'phase', or 'instrument' to determine |
---|
| 2930 | the type of template |
---|
| 2931 | :param dict G2dict: GSAS-II dict where CIF should be placed. The key |
---|
| 2932 | "CIF_template" will be used to store either a list or a string. |
---|
| 2933 | If a list, it will contain a dict and a list defining loops. If |
---|
[3011] | 2934 | an str, it will contain a file name. |
---|
[1074] | 2935 | :param function repaint: reference to a routine to be called to repaint |
---|
| 2936 | the frame after a change has been made |
---|
| 2937 | :param str title: A line of text to show at the top of the window |
---|
[3011] | 2938 | :param str defaultname: specifies the default file name to be used for |
---|
[1074] | 2939 | saving the CIF. |
---|
| 2940 | ''' |
---|
| 2941 | def __init__(self,frame,panel,tmplate,G2dict, repaint, title, defaultname=''): |
---|
| 2942 | wx.BoxSizer.__init__(self,wx.VERTICAL) |
---|
| 2943 | self.cifdefs = frame |
---|
| 2944 | self.dict = G2dict |
---|
| 2945 | self.repaint = repaint |
---|
| 2946 | templateDefName = 'template_'+tmplate+'.cif' |
---|
| 2947 | self.CIF = G2dict.get("CIF_template") |
---|
| 2948 | if defaultname: |
---|
| 2949 | self.defaultname = defaultname.encode('ascii','replace').strip().replace(' ','_') |
---|
| 2950 | self.defaultname = re.sub(r'[^a-zA-Z0-9_-]','',self.defaultname) |
---|
| 2951 | self.defaultname = tmplate + "_" + self.defaultname + ".cif" |
---|
| 2952 | else: |
---|
| 2953 | self.defaultname = '' |
---|
[3011] | 2954 | |
---|
[1074] | 2955 | txt = wx.StaticText(panel,wx.ID_ANY,title) |
---|
| 2956 | self.Add(txt,0,wx.ALIGN_CENTER) |
---|
| 2957 | # change font on title |
---|
| 2958 | txtfnt = txt.GetFont() |
---|
| 2959 | txtfnt.SetWeight(wx.BOLD) |
---|
| 2960 | txtfnt.SetPointSize(2+txtfnt.GetPointSize()) |
---|
| 2961 | txt.SetFont(txtfnt) |
---|
| 2962 | self.Add((-1,3)) |
---|
| 2963 | |
---|
| 2964 | if not self.CIF: # empty or None |
---|
| 2965 | for pth in [os.getcwd()]+sys.path: |
---|
| 2966 | fil = os.path.join(pth,self.defaultname) |
---|
| 2967 | if os.path.exists(fil) and self.defaultname: |
---|
| 2968 | self.CIF = fil |
---|
| 2969 | CIFtxt = "Template: "+self.defaultname |
---|
| 2970 | break |
---|
| 2971 | else: |
---|
| 2972 | for pth in sys.path: |
---|
| 2973 | fil = os.path.join(pth,templateDefName) |
---|
| 2974 | if os.path.exists(fil): |
---|
| 2975 | self.CIF = fil |
---|
| 2976 | CIFtxt = "Template: "+templateDefName |
---|
| 2977 | break |
---|
| 2978 | else: |
---|
| 2979 | print("Default CIF template "+self.defaultname+' not found in path!') |
---|
| 2980 | self.CIF = None |
---|
| 2981 | CIFtxt = "none! (No template found)" |
---|
| 2982 | elif type(self.CIF) is not list and type(self.CIF) is not tuple: |
---|
| 2983 | if not os.path.exists(self.CIF): |
---|
| 2984 | print("Error: template file has disappeared: "+self.CIF) |
---|
| 2985 | self.CIF = None |
---|
| 2986 | CIFtxt = "none! (file not found)" |
---|
| 2987 | else: |
---|
| 2988 | if len(self.CIF) < 50: |
---|
| 2989 | CIFtxt = "File: "+self.CIF |
---|
| 2990 | else: |
---|
| 2991 | CIFtxt = "File: ..."+self.CIF[-50:] |
---|
| 2992 | else: |
---|
| 2993 | CIFtxt = "Template is customized" |
---|
| 2994 | # show template source |
---|
| 2995 | self.Add(wx.StaticText(panel,wx.ID_ANY,CIFtxt)) |
---|
| 2996 | # show str, button to select file; button to edit (if CIF defined) |
---|
| 2997 | but = wx.Button(panel,wx.ID_ANY,"Select Template File") |
---|
| 2998 | but.Bind(wx.EVT_BUTTON,self._onGetTemplateFile) |
---|
| 2999 | hbox = wx.BoxSizer(wx.HORIZONTAL) |
---|
| 3000 | hbox.Add(but,0,0,2) |
---|
| 3001 | but = wx.Button(panel,wx.ID_ANY,"Edit Template") |
---|
| 3002 | but.Bind(wx.EVT_BUTTON,self._onEditTemplateContents) |
---|
| 3003 | if self.CIF is None: but.Disable() # nothing to edit! |
---|
| 3004 | hbox.Add(but,0,0,2) |
---|
| 3005 | self.Add(hbox) |
---|
| 3006 | def _onGetTemplateFile(self,event): |
---|
| 3007 | 'select a template file' |
---|
[2109] | 3008 | pth = G2G.GetImportPath(self.G2frame) |
---|
| 3009 | if not pth: pth = '.' |
---|
[1074] | 3010 | dlg = wx.FileDialog( |
---|
| 3011 | self.cifdefs, message="Read CIF template file", |
---|
[2109] | 3012 | defaultDir=pth, |
---|
[1074] | 3013 | defaultFile=self.defaultname, |
---|
| 3014 | wildcard="CIF (*.cif)|*.cif", |
---|
[2109] | 3015 | style=wx.OPEN) |
---|
[1074] | 3016 | ret = dlg.ShowModal() |
---|
| 3017 | fil = dlg.GetPath() |
---|
| 3018 | dlg.Destroy() |
---|
| 3019 | if ret == wx.ID_OK: |
---|
[2738] | 3020 | cf = G2IO.ReadCIF(fil) |
---|
| 3021 | if len(cf.keys()) == 0: |
---|
[3136] | 3022 | raise Exception("No CIF data_ blocks found") |
---|
[2738] | 3023 | if len(cf.keys()) != 1: |
---|
[3136] | 3024 | raise Exception('Error, CIF Template has more than one block: '+fil) |
---|
[2738] | 3025 | self.dict["CIF_template"] = fil |
---|
[1074] | 3026 | self.repaint() #EditCIFDefaults() |
---|
| 3027 | |
---|
| 3028 | def _onEditTemplateContents(self,event): |
---|
| 3029 | 'Called to edit the contents of a CIF template' |
---|
| 3030 | if type(self.CIF) is list or type(self.CIF) is tuple: |
---|
| 3031 | dblk,loopstructure = copy.deepcopy(self.CIF) # don't modify original |
---|
| 3032 | else: |
---|
| 3033 | cf = G2IO.ReadCIF(self.CIF) |
---|
| 3034 | dblk,loopstructure = CIF2dict(cf) |
---|
| 3035 | dlg = EditCIFtemplate(self.cifdefs,dblk,loopstructure,self.defaultname) |
---|
| 3036 | val = dlg.Post() |
---|
| 3037 | if val: |
---|
| 3038 | if dlg.newfile: # results saved in file |
---|
| 3039 | self.dict["CIF_template"] = dlg.newfile |
---|
| 3040 | else: |
---|
| 3041 | self.dict["CIF_template"] = [dlg.cifblk,dlg.loopstructure] |
---|
| 3042 | self.repaint() #EditCIFDefaults() # note that this does a dlg.Destroy() |
---|
| 3043 | else: |
---|
[3011] | 3044 | dlg.Destroy() |
---|
[1074] | 3045 | |
---|
| 3046 | #=============================================================================== |
---|
| 3047 | # end of misc CIF utilities |
---|
| 3048 | #=============================================================================== |
---|