source: trunk/GSASIIstrIO.py @ 4661

Last change on this file since 4661 was 4661, checked in by toby, 3 years ago

update CIF export: add rigid body, fix bug in single xtal ref tbl; picker bug on single xtal plot

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 169.3 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2020-11-28 02:48:26 +0000 (Sat, 28 Nov 2020) $
4# $Author: toby $
5# $Revision: 4661 $
6# $URL: trunk/GSASIIstrIO.py $
7# $Id: GSASIIstrIO.py 4661 2020-11-28 02:48:26Z toby $
8########### SVN repository information ###################
9'''
10*GSASIIstrIO: structure I/O routines*
11-------------------------------------
12
13Contains routines for reading from GPX files and printing to the .LST file.
14Used for refinements and in G2scriptable.
15
16Should not contain any wxpython references as this should be able to be used
17in non-GUI settings.
18
19'''
20from __future__ import division, print_function
21import platform
22import os
23import os.path as ospath
24import time
25import math
26import copy
27if '2' in platform.python_version_tuple()[0]:
28    import cPickle
29else:
30    import pickle as cPickle
31import numpy as np
32import numpy.ma as ma
33import GSASIIpath
34GSASIIpath.SetVersionNumber("$Revision: 4661 $")
35import GSASIIElem as G2el
36import GSASIIlattice as G2lat
37import GSASIIspc as G2spc
38import GSASIIobj as G2obj
39import GSASIImapvars as G2mv
40import GSASIImath as G2mth
41import GSASIIfiles as G2fil
42import GSASIIpy3 as G2py3
43
44sind = lambda x: np.sin(x*np.pi/180.)
45cosd = lambda x: np.cos(x*np.pi/180.)
46tand = lambda x: np.tan(x*np.pi/180.)
47asind = lambda x: 180.*np.arcsin(x)/np.pi
48acosd = lambda x: 180.*np.arccos(x)/np.pi
49atan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi
50   
51ateln2 = 8.0*math.log(2.0)
52
53#===============================================================================
54# Support for GPX file reading
55#===============================================================================
56def cPickleLoad(fp):
57    if '2' in platform.python_version_tuple()[0]:
58        return cPickle.load(fp)
59    else:
60       return cPickle.load(fp,encoding='latin-1')
61
62gpxIndex = {}; gpxNamelist = []; gpxSize = -1
63'''Global variables used in :func:`IndexGPX` to see if file has changed
64(gpxSize) and to index where to find each 1st-level tree item in the file.
65'''
66
67def GetFullGPX(GPXfile):
68    ''' Returns complete contents of GSASII gpx file.
69    Used in :func:`GSASIIscriptable.LoadDictFromProjFile`.
70
71    :param str GPXfile: full .gpx file name
72    :returns: Project,nameList, where
73
74      * Project (dict) is a representation of gpx file following the GSAS-II
75        tree structure for each item: key = tree name (e.g. 'Controls',
76        'Restraints', etc.), data is dict
77      * nameList (list) has names of main tree entries & subentries used to reconstruct project file
78    '''
79    return IndexGPX(GPXfile,read=True)
80
81def IndexGPX(GPXfile,read=False):
82    '''Create an index to a GPX file, optionally the file into memory.
83    The byte size of the GPX file is saved. If this routine is called
84    again, and if this size does not change, indexing is not repeated
85    since it is assumed the file has not changed (this can be overriden
86    by setting read=True).
87
88    :param str GPXfile: full .gpx file name
89    :returns: Project,nameList if read=, where
90
91      * Project (dict) is a representation of gpx file following the GSAS-II
92        tree structure for each item: key = tree name (e.g. 'Controls',
93        'Restraints', etc.), data is dict
94      * nameList (list) has names of main tree entries & subentries used to reconstruct project file
95    '''
96    global gpxSize
97    if gpxSize == os.path.getsize(GPXfile) and not read:
98        return
99    global gpxIndex
100    gpxIndex = {}
101    global gpxNamelist
102    gpxNamelist = []
103    if GSASIIpath.GetConfigValue('debug'): print("DBG: Indexing GPX file")
104    gpxSize = os.path.getsize(GPXfile)
105    fp = open(GPXfile,'rb')
106    Project = {}
107    try:
108        while True:
109            pos = fp.tell()
110            data = cPickleLoad(fp)
111            datum = data[0]
112            gpxIndex[datum[0]] = pos
113            if read: Project[datum[0]] = {'data':datum[1]}
114            gpxNamelist.append([datum[0],])
115            for datus in data[1:]:
116                if read: Project[datum[0]][datus[0]] = datus[1]
117                gpxNamelist[-1].append(datus[0])
118        # print('project load successful')
119    except EOFError:
120        pass
121    except Exception as msg:
122        G2fil.G2Print('Read Error:',msg)
123        raise Exception("Error reading file "+str(GPXfile)+". This is not a GSAS-II .gpx file")
124    finally:
125        fp.close()
126    if read: return Project,gpxNamelist   
127   
128def GetControls(GPXfile):
129    ''' Returns dictionary of control items found in GSASII gpx file
130
131    :param str GPXfile: full .gpx file name
132    :return: dictionary of control items
133    '''
134    Controls = copy.deepcopy(G2obj.DefaultControls)
135    IndexGPX(GPXfile)
136    pos = gpxIndex.get('Controls')
137    if pos is None:
138        G2fil.G2Print('Warning: Controls not found in gpx file {}'.format(GPXfile))
139        return Controls
140    fp = open(GPXfile,'rb')
141    fp.seek(pos)
142    datum = cPickleLoad(fp)[0]
143    fp.close()
144    Controls.update(datum[1])
145    return Controls
146
147def GetConstraints(GPXfile):
148    '''Read the constraints from the GPX file and interpret them
149
150    called in :func:`ReadCheckConstraints`, :func:`GSASIIstrMain.Refine`
151    and :func:`GSASIIstrMain.SeqRefine`.
152    '''
153    IndexGPX(GPXfile)
154    fl = open(GPXfile,'rb')
155    pos = gpxIndex.get('Constraints')
156    if pos is None:
157        raise Exception("No constraints in GPX file")
158    fl.seek(pos)
159    datum = cPickleLoad(fl)[0]
160    fl.close()
161    constList = []
162    for item in datum[1]:
163        if item.startswith('_'): continue
164        constList += datum[1][item]
165    constDict,fixedList,ignored = ProcessConstraints(constList)
166    if ignored:
167        G2fil.G2Print ('Warning: {} Constraints were rejected. Was a constrained phase, histogram or atom deleted?'.format(ignored))
168    return constDict,fixedList
169   
170def ProcessConstraints(constList):
171    """Interpret the constraints in the constList input into a dictionary, etc.
172    All :class:`GSASIIobj.G2VarObj` objects are mapped to the appropriate
173    phase/hist/atoms based on the object internals (random Ids). If this can't be
174    done (if a phase has been deleted, etc.), the variable is ignored.
175    If the constraint cannot be used due to too many dropped variables,
176    it is counted as ignored.
177   
178    :param list constList: a list of lists where each item in the outer list
179      specifies a constraint of some form, as described in the :mod:`GSASIIobj`
180      :ref:`Constraint definition <Constraint_definitions_table>`.
181
182    :returns:  a tuple of (constDict,fixedList,ignored) where:
183     
184      * constDict (list of dicts) contains the constraint relationships
185      * fixedList (list) contains the fixed values for each type
186        of constraint.
187      * ignored (int) counts the number of invalid constraint items
188        (should always be zero!)
189    """
190    constDict = []
191    fixedList = []
192    ignored = 0
193    for item in constList:
194        if item[-1] == 'h':
195            # process a hold
196            fixedList.append('0')
197            var = str(item[0][1])
198            if '?' not in var:
199                constDict.append({var:0.0})
200            else:
201                ignored += 1
202        elif item[-1] == 'f':
203            # process a new variable
204            fixedList.append(None)
205            D = {}
206            varyFlag = item[-2]
207            varname = item[-3]
208            for term in item[:-3]:
209                var = str(term[1])
210                if '?' not in var:
211                    D[var] = term[0]
212            if len(D) > 1:
213                # add extra dict terms for input variable name and vary flag
214                if varname is not None:
215                    varname = str(varname) # in case this is a G2VarObj
216                    if ':' in varname:
217                        D['_name'] = varname
218                    else:
219                        D['_name'] = '::' + varname
220                D['_vary'] = varyFlag == True # force to bool
221                constDict.append(D)
222            else:
223                ignored += 1
224            #constFlag[-1] = ['Vary']
225        elif item[-1] == 'c': 
226            # process a contraint relationship
227            D = {}
228            for term in item[:-3]:
229                var = str(term[1])
230                if '?' not in var:
231                    D[var] = term[0]
232            if len(D) >= 1:
233                fixedList.append(str(item[-3]))
234                constDict.append(D)
235            else:
236                ignored += 1
237        elif item[-1] == 'e':
238            # process an equivalence
239            firstmult = None
240            eqlist = []
241            for term in item[:-3]:
242                if term[0] == 0: term[0] = 1.0
243                var = str(term[1])
244                if '?' in var: continue
245                if firstmult is None:
246                    firstmult = term[0]
247                    firstvar = var
248                else:
249                    eqlist.append([var,firstmult/term[0]])
250            if len(eqlist) > 0:
251                G2mv.StoreEquivalence(firstvar,eqlist,False)
252            else:
253                ignored += 1
254        else:
255            ignored += 1
256    return constDict,fixedList,ignored
257
258def ReadCheckConstraints(GPXfile, seqHist=None):
259    '''Load constraints and related info and return any error or warning messages
260    This is done from the GPX file rather than the tree.
261
262    :param dict seqHist: defines a specific histogram to be loaded for a sequential
263       refinement, if None (default) all are loaded.
264    '''
265    # init constraints
266    G2mv.InitVars()   
267    # get variables
268    Histograms,Phases = GetUsedHistogramsAndPhases(GPXfile)
269    if not Phases:
270        return 'Error: No phases or no histograms in phases!',''
271    if not Histograms:
272        return 'Error: no diffraction data',''
273    constrDict,fixedList = GetConstraints(GPXfile) # load user constraints before internally generated ones
274    if seqHist: Histograms = {seqHist:Histograms[seqHist]}  # sequential fit: only need one histogram
275    rigidbodyDict = GetRigidBodies(GPXfile)
276    rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
277    rbVary,rbDict = GetRigidBodyModels(rigidbodyDict,Print=False)
278    Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,MFtables,maxSSwave = \
279        GetPhaseData(Phases,RestraintDict=None,rbIds=rbIds,Print=False) # generates atom symmetry constraints
280    hapVary,hapDict,controlDict = GetHistogramPhaseData(Phases,Histograms,Print=False,resetRefList=False)
281    histVary,histDict,controlDict = GetHistogramData(Histograms,Print=False)
282    varyList = rbVary+phaseVary+hapVary+histVary
283    msg = G2mv.EvaluateMultipliers(constrDict,phaseDict,hapDict,histDict)
284    if msg:
285        return 'Unable to interpret multiplier(s): '+msg,''
286    errmsg, warnmsg = G2mv.CheckConstraints(varyList,constrDict,fixedList)
287    if errmsg:
288        # print some diagnostic info on the constraints
289        G2fil.G2Print('Error in constraints:\n'+errmsg+
290              '\nRefinement not possible due to conflict in constraints, see below:\n')
291        G2fil.G2Print(G2mv.VarRemapShow(varyList,True),mode='error')
292    return errmsg, warnmsg
293   
294def makeTwinFrConstr(Phases,Histograms,hapVary):
295    TwConstr = []
296    TwFixed = []
297    for Phase in Phases:
298        pId = Phases[Phase]['pId']
299        for Histogram in Phases[Phase]['Histograms']:
300            try:
301                hId = Histograms[Histogram]['hId']
302                phfx = '%d:%d:'%(pId,hId)
303                if phfx+'TwinFr:0' in hapVary:
304                    TwFixed.append('1.0')     #constraint value
305                    nTwin = len(Phases[Phase]['Histograms'][Histogram]['Twins'])
306                    TwConstr.append({phfx+'TwinFr:'+str(i):'1.0' for i in range(nTwin)})
307            except KeyError:    #unused histograms?
308                pass
309    return TwConstr,TwFixed   
310   
311def GetRestraints(GPXfile):
312    '''Read the restraints from the GPX file.
313    Throws an exception if not found in the .GPX file
314    '''
315    IndexGPX(GPXfile)
316    fl = open(GPXfile,'rb')
317    pos = gpxIndex.get('Restraints')
318    if pos is None:
319        raise Exception("No Restraints in GPX file")
320    fl.seek(pos)
321    datum = cPickleLoad(fl)[0]
322    fl.close()
323    return datum[1]
324   
325def GetRigidBodies(GPXfile):
326    '''Read the rigid body models from the GPX file
327    '''
328    IndexGPX(GPXfile)
329    fl = open(GPXfile,'rb')
330    pos = gpxIndex.get('Rigid bodies')
331    if pos is None:
332        raise Exception("No Rigid bodies in GPX file")
333    fl.seek(pos)
334    datum = cPickleLoad(fl)[0]
335    fl.close()
336    return datum[1]
337       
338def GetFprime(controlDict,Histograms):
339    'Needs a doc string'
340    FFtables = controlDict['FFtables']
341    if not FFtables:
342        return
343    histoList = list(Histograms.keys())
344    histoList.sort()
345    for histogram in histoList:
346        if histogram[:4] in ['PWDR','HKLF']:
347            Histogram = Histograms[histogram]
348            hId = Histogram['hId']
349            hfx = ':%d:'%(hId)
350            if 'X' in controlDict[hfx+'histType']:
351                keV = controlDict[hfx+'keV']
352                for El in FFtables:
353                    Orbs = G2el.GetXsectionCoeff(El.split('+')[0].split('-')[0])
354                    FP,FPP,Mu = G2el.FPcalc(Orbs, keV)
355                    FFtables[El][hfx+'FP'] = FP
356                    FFtables[El][hfx+'FPP'] = FPP
357                   
358def PrintFprime(FFtables,pfx,pFile):
359    pFile.write('\n Resonant form factors:(ref: D.T. Cromer & D.A. Liberman (1981), Acta Cryst. A37, 267-268.)\n')
360    Elstr = ' Element:'
361    FPstr = " f'     :"
362    FPPstr = ' f"     :'
363    for El in FFtables:
364        Elstr += ' %8s'%(El)
365        FPstr += ' %8.3f'%(FFtables[El][pfx+'FP'])
366        FPPstr += ' %8.3f'%(FFtables[El][pfx+'FPP'])
367    pFile.write(Elstr+'\n')
368    pFile.write(FPstr+'\n')
369    pFile.write(FPPstr+'\n')
370
371def PrintISOmodes(pFile,Phases,parmDict,sigDict):
372    '''Prints the values for the ISODISTORT modes into the project's
373    .lst file after a refinement.
374    '''
375    for phase in Phases:
376        if 'ISODISTORT' not in Phases[phase]: continue
377        data = Phases[phase]
378        ISO = data['ISODISTORT']
379        if 'G2VarList' in ISO:
380            deltaList = []
381            for gv,Ilbl in zip(ISO['G2VarList'],ISO['IsoVarList']):
382                dvar = gv.varname()
383                var = dvar.replace('::dA','::A')
384                albl = Ilbl[:Ilbl.rfind('_')]
385                v = Ilbl[Ilbl.rfind('_')+1:]
386                pval = ISO['ParentStructure'][albl][['dx','dy','dz'].index(v)]
387                if var in parmDict:
388                    cval = parmDict[var]
389                else:
390                    print('PrintISOmodes Error: Atom not found',"No value found for parameter "+str(var))
391                    return
392                deltaList.append(cval-pval)
393            modeVals = np.inner(ISO['Var2ModeMatrix'],deltaList)
394           
395        if 'G2OccVarList' in ISO:
396            deltaOccList = []
397            for gv,Ilbl in zip(ISO['G2OccVarList'],ISO['OccVarList']):
398                var = gv.varname()
399                albl = Ilbl[:Ilbl.rfind('_')]
400                pval = ISO['BaseOcc'][albl]
401                if var in parmDict:
402                    cval = parmDict[var]
403                else:
404                    print('PrintISOmodes Error: Atom not found',"No value found for parameter "+str(var))
405                    return
406                deltaOccList.append(cval-pval)
407            modeOccVals = np.inner(ISO['Var2OccMatrix'],deltaOccList)
408           
409        if 'G2VarList' in ISO:
410            pFile.write('\n ISODISTORT Displacive Modes for phase {}\n'.format(data['General'].get('Name','')))
411            l = str(max([len(i) for i in ISO['IsoModeList']])+3)
412            fmt = '  {:'+l+'}{}'
413            for var,val,norm,G2mode in zip(
414                    ISO['IsoModeList'],modeVals,ISO['NormList'],ISO['G2ModeList'] ):
415                try:
416                    value = G2py3.FormatSigFigs(val/norm)
417                    if str(G2mode) in sigDict:
418                        value = G2mth.ValEsd(val/norm,sigDict[str(G2mode)]/norm)
419                except TypeError:
420                    value = '?'
421                pFile.write(fmt.format(var,value)+'\n')
422               
423        if 'G2OccVarList' in ISO:
424            pFile.write('\n ISODISTORT Occupancy Modes for phase {}\n'.format(data['General'].get('Name','')))
425            l = str(max([len(i) for i in ISO['OccModeList']])+3)
426            fmt = '  {:'+l+'}{}'
427            for var,val,norm,G2mode in zip(
428                    ISO['OccModeList'],modeOccVals,ISO['OccNormList'],ISO['G2OccModeList'] ):
429                try:
430                    value = G2py3.FormatSigFigs(val/norm)
431                    if str(G2mode) in sigDict:
432                        value = G2mth.ValEsd(val/norm,sigDict[str(G2mode)]/norm)
433                except TypeError:
434                    value = '?'
435                pFile.write(fmt.format(var,value)+'\n')
436   
437def GetPhaseNames(GPXfile):
438    ''' Returns a list of phase names found under 'Phases' in GSASII gpx file
439
440    :param str GPXfile: full .gpx file name
441    :return: list of phase names
442    '''
443    IndexGPX(GPXfile)
444    fl = open(GPXfile,'rb')
445    pos = gpxIndex.get('Phases')
446    if pos is None:
447        raise Exception("No Phases in GPX file")
448    fl.seek(pos)
449    data = cPickleLoad(fl)
450    fl.close()
451    return [datus[0] for datus in data[1:]]
452
453def GetAllPhaseData(GPXfile,PhaseName):
454    ''' Returns the entire dictionary for PhaseName from GSASII gpx file
455
456    :param str GPXfile: full .gpx file name
457    :param str PhaseName: phase name
458    :return: phase dictionary or None if PhaseName is not present
459    '''       
460    IndexGPX(GPXfile)
461    fl = open(GPXfile,'rb')
462    pos = gpxIndex.get('Phases')
463    if pos is None:
464        raise Exception("No Phases in GPX file")
465    fl.seek(pos)
466    data = cPickleLoad(fl)
467    fl.close()
468
469    for datus in data[1:]:
470        if datus[0] == PhaseName:
471            return datus[1]
472   
473def GetHistograms(GPXfile,hNames):
474    """ Returns a dictionary of histograms found in GSASII gpx file
475
476    :param str GPXfile: full .gpx file name
477    :param str hNames: list of histogram names
478    :return: dictionary of histograms (types = PWDR & HKLF)
479
480    """
481    IndexGPX(GPXfile)
482    fl = open(GPXfile,'rb')
483    Histograms = {}
484    for hist in hNames:
485        pos = gpxIndex.get(hist)
486        if pos is None:
487            raise Exception("Histogram {} not found in GPX file".format(hist))
488        fl.seek(pos)
489        data = cPickleLoad(fl)
490        datum = data[0]
491        if 'PWDR' in hist[:4]:
492            PWDRdata = {}
493            PWDRdata.update(datum[1][0])        #weight factor
494            PWDRdata['Data'] = ma.array(ma.getdata(datum[1][1]))          #masked powder data arrays/clear previous masks
495            PWDRdata[data[2][0]] = data[2][1]       #Limits & excluded regions (if any)
496            PWDRdata[data[3][0]] = data[3][1]       #Background
497            PWDRdata[data[4][0]] = data[4][1]       #Instrument parameters
498            PWDRdata[data[5][0]] = data[5][1]       #Sample parameters
499            try:
500               PWDRdata[data[9][0]] = data[9][1]       #Reflection lists might be missing
501            except IndexError:
502                PWDRdata['Reflection Lists'] = {}
503            PWDRdata['Residuals'] = {}
504            Histograms[hist] = PWDRdata
505        elif 'HKLF' in hist[:4]:
506            HKLFdata = {}
507            HKLFdata.update(datum[1][0])        #weight factor
508#patch
509            if 'list' in str(type(datum[1][1])):
510            #if isinstance(datum[1][1],list):
511                RefData = {'RefList':[],'FF':{}}
512                for ref in datum[1][1]:
513                    RefData['RefList'].append(ref[:11]+[ref[13],])
514                RefData['RefList'] = np.array(RefData['RefList'])
515                datum[1][1] = RefData
516#end patch
517            datum[1][1]['FF'] = {}
518            HKLFdata['Data'] = datum[1][1]
519            HKLFdata[data[1][0]] = data[1][1]       #Instrument parameters
520            HKLFdata['Reflection Lists'] = None
521            HKLFdata['Residuals'] = {}
522            Histograms[hist] = HKLFdata           
523    fl.close()
524    return Histograms
525   
526def GetHistogramNames(GPXfile,hTypes):
527    """ Returns a list of histogram names found in a GSAS-II .gpx file that
528    match specifed histogram types. Names are returned in the order they
529    appear in the file.
530
531    :param str GPXfile: full .gpx file name
532    :param str hTypes: list of histogram types
533    :return: list of histogram names (types = PWDR & HKLF)
534
535    """
536    IndexGPX(GPXfile)
537    return [n[0] for n in gpxNamelist if n[0][:4] in hTypes]
538   
539def GetUsedHistogramsAndPhases(GPXfile):
540    ''' Returns all histograms that are found in any phase
541    and any phase that uses a histogram. This also
542    assigns numbers to used phases and histograms by the
543    order they appear in the file.
544
545    :param str GPXfile: full .gpx file name
546    :returns: (Histograms,Phases)
547
548     * Histograms = dictionary of histograms as {name:data,...}
549     * Phases = dictionary of phases that use histograms
550
551    '''
552    phaseNames = GetPhaseNames(GPXfile)
553    histoList = GetHistogramNames(GPXfile,['PWDR','HKLF'])
554    allHistograms = GetHistograms(GPXfile,histoList)
555    phaseData = {}
556    for name in phaseNames: 
557        phaseData[name] =  GetAllPhaseData(GPXfile,name)
558    Histograms = {}
559    Phases = {}
560    for phase in phaseData:
561        Phase = phaseData[phase]
562        if Phase['General']['Type'] == 'faulted': continue      #don't use faulted phases!
563        if Phase['Histograms']:
564            for hist in Phase['Histograms']:
565                if 'Use' not in Phase['Histograms'][hist]:      #patch
566                    Phase['Histograms'][hist]['Use'] = True
567                if Phase['Histograms'][hist]['Use'] and phase not in Phases:
568                    pId = phaseNames.index(phase)
569                    Phase['pId'] = pId
570                    Phases[phase] = Phase
571                if hist not in Histograms and Phase['Histograms'][hist]['Use']:
572                    try:
573                        Histograms[hist] = allHistograms[hist]
574                        hId = histoList.index(hist)
575                        Histograms[hist]['hId'] = hId
576                    except KeyError: # would happen if a referenced histogram were
577                        # renamed or deleted
578                        G2fil.G2Print('Warning: For phase "'+phase+
579                              '" unresolved reference to histogram "'+hist+'"')
580    # load the fix background info into the histograms
581    for hist in Histograms:
582        if 'Background' not in Histograms[hist]: continue
583        fixedBkg = Histograms[hist]['Background'][1].get('background PWDR')
584        if fixedBkg:
585            if not fixedBkg[0]: continue
586            # patch: add refinement flag, if needed
587            if len(fixedBkg) == 2: fixedBkg += [False]
588            h = Histograms[hist]['Background'][1]
589            try:
590                Limits = Histograms[hist]['Limits'][1]
591                x = Histograms[hist]['Data'][0]
592                xB = np.searchsorted(x,Limits[0])
593                xF = np.searchsorted(x,Limits[1])+1
594                h['_fixedValues'] = allHistograms[fixedBkg[0]]['Data'][1][xB:xF]
595                h['_fixedMult'],h['_fixedVary'] = fixedBkg[1:]
596            except KeyError: # would happen if a referenced histogram were renamed or deleted
597                G2fil.G2Print('Warning: For hist "{}" unresolved background reference to hist "{}"'
598                          .format(hist,fixedBkg[0]))
599    G2obj.IndexAllIds(Histograms=Histograms,Phases=Phases)
600    return Histograms,Phases
601   
602def getBackupName(GPXfile,makeBack):
603    '''
604    Get the name for the backup .gpx file name
605   
606    :param str GPXfile: full .gpx file name
607    :param bool makeBack: if True the name of a new file is returned, if
608      False the name of the last file that exists is returned
609    :returns: the name of a backup file
610   
611    '''
612    GPXpath,GPXname = ospath.split(GPXfile)
613    if GPXpath == '': GPXpath = '.'
614    Name = ospath.splitext(GPXname)[0]
615    files = os.listdir(GPXpath)
616    last = 0
617    for name in files:
618        name = name.split('.')
619        if len(name) == 3 and name[0] == Name and 'bak' in name[1]:
620            if makeBack:
621                last = max(last,int(name[1].strip('bak'))+1)
622            else:
623                last = max(last,int(name[1].strip('bak')))
624    GPXback = ospath.join(GPXpath,ospath.splitext(GPXname)[0]+'.bak'+str(last)+'.gpx')
625    return GPXback   
626       
627def GPXBackup(GPXfile,makeBack=True):
628    '''
629    makes a backup of the specified .gpx file
630   
631    :param str GPXfile: full .gpx file name
632    :param bool makeBack: if True (default), the backup is written to
633      a new file; if False, the last backup is overwritten
634    :returns: the name of the backup file that was written
635    '''
636    import distutils.file_util as dfu
637    GPXback = getBackupName(GPXfile,makeBack)
638    tries = 0
639    while True:
640        try:
641            dfu.copy_file(GPXfile,GPXback)
642            break
643        except:
644            tries += 1
645            if tries > 10:
646                return GPXfile  #failed!
647            time.sleep(1)           #just wait a second!         
648    return GPXback
649
650def SetUsedHistogramsAndPhases(GPXfile,Histograms,Phases,RigidBodies,CovData,parmFrozenList,makeBack=True):
651    ''' Updates gpxfile from all histograms that are found in any phase
652    and any phase that used a histogram. Also updates rigid body definitions.
653    This is used for non-sequential fits, but not for sequential fitting.
654
655    :param str GPXfile: full .gpx file name
656    :param dict Histograms: dictionary of histograms as {name:data,...}
657    :param dict Phases: dictionary of phases that use histograms
658    :param dict RigidBodies: dictionary of rigid bodies
659    :param dict CovData: dictionary of refined variables, varyList, & covariance matrix
660    :param list parmFrozenList: list of parameters (as str) that are frozen
661      due to limits; converted to :class:`GSASIIobj.G2VarObj` objects.
662    :param bool makeBack: True if new backup of .gpx file is to be made; else
663      use the last one made
664    '''
665                       
666    import distutils.file_util as dfu
667    GPXback = GPXBackup(GPXfile,makeBack)
668    G2fil.G2Print ('Read from file:'+GPXback)
669    G2fil.G2Print ('Save to file  :'+GPXfile)
670    infile = open(GPXback,'rb')
671    outfile = open(GPXfile,'wb')
672    while True:
673        try:
674            data = cPickleLoad(infile)
675        except EOFError:
676            break
677        datum = data[0]
678#        print 'read: ',datum[0]
679        if datum[0] == 'Phases':
680            for iphase in range(len(data)):
681                if data[iphase][0] in Phases:
682                    phaseName = data[iphase][0]
683                    data[iphase][1].update(Phases[phaseName])
684        elif datum[0] == 'Covariance':
685            data[0][1] = CovData
686        elif datum[0] == 'Rigid bodies':
687            data[0][1] = RigidBodies
688        elif datum[0] == 'Controls':
689            Controls = data[0][1]
690            if 'parmFrozen' not in Controls:
691                Controls['parmFrozen'] = {}
692            Controls['parmFrozen']['FrozenList'] = [
693                    i if type(i) is G2obj.G2VarObj
694                    else G2obj.G2VarObj(i)
695                    for i in parmFrozenList]
696        try:
697            histogram = Histograms[datum[0]]
698#            print 'found ',datum[0]
699            data[0][1][1] = histogram['Data']
700            data[0][1][0].update(histogram['Residuals'])
701            for datus in data[1:]:
702#                print '    read: ',datus[0]
703                if datus[0] in ['Instrument Parameters','Sample Parameters','Reflection Lists']:
704                    datus[1] = histogram[datus[0]]
705                if datus[0] == 'Background': # remove fixed background from file
706                    d1 = {key:histogram['Background'][1][key]
707                              for key in histogram['Background'][1]
708                              if not key.startswith('_fixed')}               
709                    datus[1] = copy.deepcopy(histogram['Background'])
710                    datus[1][1] = d1
711        except KeyError:
712            pass
713        try:                       
714            cPickle.dump(data,outfile,1)
715        except AttributeError:
716            G2fil.G2Print ('ERROR - bad data in least squares result')
717            infile.close()
718            outfile.close()
719            dfu.copy_file(GPXback,GPXfile)
720            G2fil.G2Print ('GPX file save failed - old version retained',mode='error')
721            return
722       
723    infile.close()
724    outfile.close()
725           
726    G2fil.G2Print ('GPX file save successful')
727   
728def GetSeqResult(GPXfile):
729    '''
730    Returns the sequential results table information from a GPX file.
731    Called at the beginning of :meth:`GSASIIstrMain.SeqRefine`
732   
733    :param str GPXfile: full .gpx file name
734    :returns: a dict containing the sequential results table
735    '''
736    IndexGPX(GPXfile)
737    pos = gpxIndex.get('Sequential results')
738    if pos is None:
739        return {}
740    fl = open(GPXfile,'rb')
741    fl.seek(pos)
742    datum = cPickleLoad(fl)[0]
743    fl.close()
744    return datum[1]
745   
746def SetupSeqSavePhases(GPXfile):
747    '''Initialize the files used to save intermediate results from
748    sequential fits.
749    '''
750    IndexGPX(GPXfile)
751    # load initial Phase results from GPX
752    fl = open(GPXfile,'rb')
753    pos = gpxIndex.get('Phases')
754    if pos is None:
755        raise Exception("No Phases in GPX file")
756    fl.seek(pos)
757    data = cPickleLoad(fl)
758    fl.close()
759    # create GPX-like file to store latest Phase info; init with start vals
760    GPXphase = os.path.splitext(GPXfile)[0]+'.seqPhase'
761    fp = open(GPXphase,'wb')
762    cPickle.dump(data,fp,1)
763    fp.close()
764    # create empty file for histogram info
765    GPXhist = os.path.splitext(GPXfile)[0]+'.seqHist'
766    fp = open(GPXhist,'wb')
767    fp.close()
768
769def SaveUpdatedHistogramsAndPhases(GPXfile,Histograms,Phases,RigidBodies,CovData,parmFrozen):
770    '''
771    Save phase and histogram information into "pseudo-gpx" files. The phase
772    information is overwritten each time this is called, but histogram information is
773    appended after each sequential step.
774
775    :param str GPXfile: full .gpx file name
776    :param dict Histograms: dictionary of histograms as {name:data,...}
777    :param dict Phases: dictionary of phases that use histograms
778    :param dict RigidBodies: dictionary of rigid bodies
779    :param dict CovData: dictionary of refined variables, varyList, & covariance matrix
780    :param dict parmFrozen: dict with frozen parameters for all phases
781      and histograms (specified as str values)
782    '''
783                       
784    import distutils.file_util as dfu
785   
786    GPXphase = os.path.splitext(GPXfile)[0]+'.seqPhase'
787    fp = open(GPXphase,'rb')
788    data = cPickleLoad(fp) # first block in file should be Phases
789    if data[0][0] != 'Phases':
790        raise Exception('Unexpected block in {} file. How did this happen?'
791                            .format(GPXphase))
792    fp.close()
793    # update previous phase info
794    for datum in data[1:]: 
795        if datum[0] in Phases:
796            datum[1].update(Phases[datum[0]])
797    # save latest Phase/refinement info
798    fp = open(GPXphase,'wb')
799    cPickle.dump(data,fp,1)
800    cPickle.dump([['Covariance',CovData]],fp,1)
801    cPickle.dump([['Rigid bodies',RigidBodies]],fp,1)
802    cPickle.dump([['parmFrozen',parmFrozen]],fp,1)
803    fp.close()
804    # create an entry that looks like a PWDR tree item
805    for key in Histograms:
806        if key.startswith('PWDR '):
807            break
808    else:
809        raise Exception('No PWDR entry in Histogram dict!')
810    histname = key
811    hist = copy.deepcopy(Histograms[key])
812    xfer_dict = {'Index Peak List': [[], []],
813                   'Comments': [],
814                   'Unit Cells List': [],
815                   'Peak List': {'peaks': [], 'sigDict': {}},
816                   }
817    histData = hist['Data']
818    del hist['Data']
819    for key in ('Limits','Background','Instrument Parameters',
820                    'Sample Parameters','Reflection Lists'):
821        xfer_dict[key] = hist[key]
822        if key == 'Background':  # remove fixed background from file
823            xfer_dict['Background'][1] = {k:hist['Background'][1][k]
824                      for k in hist['Background'][1]
825                      if not k.startswith('_fixed')}               
826        del hist[key]
827    # xform into a gpx-type entry
828    data = []
829    data.append([histname,[hist,histData,histname]])       
830    for key in ['Comments','Limits','Background','Instrument Parameters',
831             'Sample Parameters','Peak List','Index Peak List',
832             'Unit Cells List','Reflection Lists']:
833        data.append([key,xfer_dict[key]])
834    # append histogram to histogram info
835    GPXhist = os.path.splitext(GPXfile)[0]+'.seqHist'
836    fp = open(GPXhist,'ab')
837    cPickle.dump(data,fp,1)
838    fp.close()
839    return
840   
841def SetSeqResult(GPXfile,Histograms,SeqResult):
842    '''
843    Places the sequential results information into a GPX file
844    after a refinement has been completed.
845    Called at the end of :meth:`GSASIIstrMain.SeqRefine`
846
847    :param str GPXfile: full .gpx file name
848    '''
849    GPXback = GPXBackup(GPXfile)
850    G2fil.G2Print ('Read from file:'+GPXback)
851    G2fil.G2Print ('Save to file  :'+GPXfile)
852    GPXphase = os.path.splitext(GPXfile)[0]+'.seqPhase'
853    fp = open(GPXphase,'rb')
854    data = cPickleLoad(fp) # first block in file should be Phases
855    if data[0][0] != 'Phases':
856        raise Exception('Unexpected block in {} file. How did this happen?'.format(GPXphase))
857    Phases = {}
858    for name,vals in data[1:]:
859        Phases[name] = vals       
860    name,CovData = cPickleLoad(fp)[0] # 2nd block in file should be Covariance
861    name,RigidBodies = cPickleLoad(fp)[0] # 3rd block in file should be Rigid Bodies
862    name,parmFrozenDict = cPickleLoad(fp)[0] # 4th block in file should be frozen parameters
863    fp.close()
864    GPXhist = os.path.splitext(GPXfile)[0]+'.seqHist'
865    hist = open(GPXhist,'rb')
866    # build an index to the GPXhist file
867    histIndex = {}
868    while True:
869        loc = hist.tell()
870        try:
871            datum = cPickleLoad(hist)[0]
872        except EOFError:
873            break
874        histIndex[datum[0]] = loc
875
876    infile = open(GPXback,'rb')
877    outfile = open(GPXfile,'wb')
878    while True:
879        try:
880            data = cPickleLoad(infile)
881        except EOFError:
882            break
883        datum = data[0]
884        if datum[0] == 'Sequential results':
885            data[0][1] = SeqResult
886        elif datum[0] == 'Phases':
887            for pdata in data[1:]:
888                if pdata[0] in Phases:
889                    pdata[1].update(Phases[pdata[0]])
890        elif datum[0] == 'Covariance':
891            data[0][1] = CovData
892        elif datum[0] == 'Rigid bodies':
893            data[0][1] = RigidBodies
894        elif datum[0] == 'Controls': # reset the Copy Next flag after a sequential fit
895            Controls = data[0][1]
896            Controls['Copy2Next'] = False
897            for key in parmFrozenDict:
898                Controls['parmFrozen'][key] = [
899                    i if type(i) is G2obj.G2VarObj
900                    else G2obj.G2VarObj(i)
901                    for i in parmFrozenDict[key]]
902        elif datum[0] in histIndex:
903            hist.seek(histIndex[datum[0]])
904            hdata = cPickleLoad(hist)
905            if data[0][0] != hdata[0][0]:
906                G2fil.G2Print('Error! Updating {} with {}'.format(data[0][0],hdata[0][0]))
907            data[0] = hdata[0]
908            xferItems = ['Background','Instrument Parameters','Sample Parameters','Reflection Lists']
909            hItems = {name:j+1 for j,(name,val) in enumerate(hdata[1:]) if name in xferItems}
910            for j,(name,val) in enumerate(data[1:]):
911                if name not in xferItems: continue
912                data[j+1][1] = hdata[hItems[name]][1]
913        cPickle.dump(data,outfile,1)
914    hist.close()
915    infile.close()
916    outfile.close()
917    # clean up tmp files
918    try:
919        os.remove(GPXphase)
920    except:
921        G2fil.G2Print('Warning: unable to delete {}'.format(GPXphase))
922    try:
923        os.remove(GPXhist)
924    except:
925        G2fil.G2Print('Warning: unable to delete {}'.format(GPXhist))
926    G2fil.G2Print ('GPX file merge completed')
927
928#==============================================================================
929# Refinement routines
930#==============================================================================
931def ShowBanner(pFile=None):
932    'Print authorship, copyright and citation notice'
933    pFile.write(80*'*'+'\n')
934    pFile.write('   General Structure Analysis System-II Crystal Structure Refinement\n')
935    pFile.write('              by Robert B. Von Dreele & Brian H. Toby\n')
936    pFile.write('                Argonne National Laboratory(C), 2010\n')
937    pFile.write(' This product includes software developed by the UChicago Argonne, LLC,\n')
938    pFile.write('            as Operator of Argonne National Laboratory.\n')
939    pFile.write('                          Please cite:\n')
940    pFile.write('   B.H. Toby & R.B. Von Dreele, J. Appl. Cryst. 46, 544-549 (2013)\n')
941
942    pFile.write(80*'*'+'\n')
943
944def ShowControls(Controls,pFile=None,SeqRef=False,preFrozenCount=0):
945    'Print controls information'
946    pFile.write(' Least squares controls:\n')
947    pFile.write(' Refinement type: %s\n'%Controls['deriv type'])
948    if 'Hessian' in Controls['deriv type']:
949        pFile.write(' Maximum number of cycles: %d\n'%Controls['max cyc'])
950    else:
951        pFile.write(' Minimum delta-M/M for convergence: %.2g\n'%(Controls['min dM/M']))
952    pFile.write(' Regularize hydrogens (if any): %s\n'%Controls.get('HatomFix',False))
953    pFile.write(' Initial shift factor: %.3f\n'%(Controls['shift factor']))
954    if SeqRef:
955        pFile.write(' Sequential refinement controls:\n')
956        pFile.write(' Copy of histogram results to next: %s\n'%(Controls['Copy2Next']))
957        pFile.write(' Process histograms in reverse order: %s\n'%(Controls['Reverse Seq']))
958    if preFrozenCount:
959        pFile.write('\n Starting refinement with {} Frozen variables\n\n'.format(preFrozenCount))
960   
961def GetPawleyConstr(SGLaue,PawleyRef,im,pawleyVary):
962    'needs a doc string'
963#    if SGLaue in ['-1','2/m','mmm']:
964#        return                      #no Pawley symmetry required constraints
965    eqvDict = {}
966    for i,varyI in enumerate(pawleyVary):
967        eqvDict[varyI] = []
968        refI = int(varyI.split(':')[-1])
969        ih,ik,il = PawleyRef[refI][:3]
970        dspI = PawleyRef[refI][4+im]
971        for varyJ in pawleyVary[i+1:]:
972            refJ = int(varyJ.split(':')[-1])
973            jh,jk,jl = PawleyRef[refJ][:3]
974            dspJ = PawleyRef[refJ][4+im]
975            if SGLaue in ['4/m','4/mmm']:
976                isum = ih**2+ik**2
977                jsum = jh**2+jk**2
978                if abs(il) == abs(jl) and isum == jsum:
979                    eqvDict[varyI].append(varyJ) 
980            elif SGLaue in ['3R','3mR']:
981                isum = ih**2+ik**2+il**2
982                jsum = jh**2+jk**2+jl**2
983                isum2 = ih*ik+ih*il+ik*il
984                jsum2 = jh*jk+jh*jl+jk*jl
985                if isum == jsum and isum2 == jsum2:
986                    eqvDict[varyI].append(varyJ) 
987            elif SGLaue in ['3','3m1','31m','6/m','6/mmm']:
988                isum = ih**2+ik**2+ih*ik
989                jsum = jh**2+jk**2+jh*jk
990                if abs(il) == abs(jl) and isum == jsum:
991                    eqvDict[varyI].append(varyJ) 
992            elif SGLaue in ['m3','m3m']:
993                isum = ih**2+ik**2+il**2
994                jsum = jh**2+jk**2+jl**2
995                if isum == jsum:
996                    eqvDict[varyI].append(varyJ)
997            elif abs(dspI-dspJ)/dspI < 1.e-4:
998                eqvDict[varyI].append(varyJ) 
999    for item in pawleyVary:
1000        if eqvDict[item]:
1001            for item2 in pawleyVary:
1002                if item2 in eqvDict[item]:
1003                    eqvDict[item2] = []
1004            G2mv.StoreEquivalence(item,eqvDict[item])
1005                   
1006def cellVary(pfx,SGData): 
1007    '''Creates equivalences for a phase based on the Laue class.
1008    Returns a list of A tensor terms that are non-zero.
1009    '''
1010    if SGData['SGLaue'] in ['-1',]:
1011        return [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A3',pfx+'A4',pfx+'A5']
1012    elif SGData['SGLaue'] in ['2/m',]:
1013        if SGData['SGUniq'] == 'a':
1014            return [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A5']
1015        elif SGData['SGUniq'] == 'b':
1016            return [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A4']
1017        else:
1018            return [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A3']
1019    elif SGData['SGLaue'] in ['mmm',]:
1020        return [pfx+'A0',pfx+'A1',pfx+'A2']
1021    elif SGData['SGLaue'] in ['4/m','4/mmm']:
1022        G2mv.StoreEquivalence(pfx+'A0',(pfx+'A1',))
1023        return [pfx+'A0',pfx+'A1',pfx+'A2']
1024    elif SGData['SGLaue'] in ['6/m','6/mmm','3m1', '31m', '3']:
1025        G2mv.StoreEquivalence(pfx+'A0',(pfx+'A1',pfx+'A3',))
1026        return [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A3']
1027    elif SGData['SGLaue'] in ['3R', '3mR']:
1028        G2mv.StoreEquivalence(pfx+'A0',(pfx+'A1',pfx+'A2',))
1029        G2mv.StoreEquivalence(pfx+'A3',(pfx+'A4',pfx+'A5',))
1030        return [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A3',pfx+'A4',pfx+'A5']                       
1031    elif SGData['SGLaue'] in ['m3m','m3']:
1032        G2mv.StoreEquivalence(pfx+'A0',(pfx+'A1',pfx+'A2',))
1033        return [pfx+'A0',pfx+'A1',pfx+'A2']
1034       
1035def modVary(pfx,SSGData):
1036    vary = []
1037    for i,item in enumerate(SSGData['modSymb']):
1038        if item in ['a','b','g']:
1039            vary.append(pfx+'mV%d'%(i))
1040    return vary
1041       
1042################################################################################
1043##### Rigid Body Models and not General.get('doPawley')
1044################################################################################
1045       
1046def GetRigidBodyModels(rigidbodyDict,Print=True,pFile=None):
1047    'Get Rigid body info from tree entry and print it to .LST file'
1048   
1049    def PrintResRBModel(RBModel):
1050        pFile.write('Residue RB name: %s no.atoms: %d, No. times used: %d\n'%
1051            (RBModel['RBname'],len(RBModel['rbTypes']),RBModel['useCount']))
1052        for i in WriteResRBModel(RBModel):
1053            pFile.write(i)
1054       
1055    def PrintVecRBModel(RBModel):
1056        pFile.write('Vector RB name: %s no.atoms: %d No. times used: %d\n'%
1057            (RBModel['RBname'],len(RBModel['rbTypes']),RBModel['useCount']))
1058        for i in WriteVecRBModel(RBModel):
1059            pFile.write(i)
1060        pFile.write('Orientation defined by: atom %s -> atom %s & atom %s -> atom %s\n'%
1061            (RBModel['rbRef'][0],RBModel['rbRef'][1],RBModel['rbRef'][0],RBModel['rbRef'][2]))
1062           
1063    rbVary = []
1064    rbDict = {}
1065    rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
1066    if len(rbIds['Vector']):
1067        for irb,item in enumerate(rbIds['Vector']):
1068            if rigidbodyDict['Vector'][item]['useCount']:
1069                RBmags = rigidbodyDict['Vector'][item]['VectMag']
1070                RBrefs = rigidbodyDict['Vector'][item]['VectRef']
1071                for i,[mag,ref] in enumerate(zip(RBmags,RBrefs)):
1072                    pid = '::RBV;'+str(i)+':'+str(irb)
1073                    rbDict[pid] = mag
1074                    if ref:
1075                        rbVary.append(pid)
1076                if Print:
1077                    pFile.write('\nVector rigid body model:\n')
1078                    PrintVecRBModel(rigidbodyDict['Vector'][item])
1079    if len(rbIds['Residue']):
1080        for item in rbIds['Residue']:
1081            if rigidbodyDict['Residue'][item]['useCount']:
1082                if Print:
1083                    pFile.write('\nResidue rigid body model:\n')
1084                    PrintResRBModel(rigidbodyDict['Residue'][item])
1085    return rbVary,rbDict
1086   
1087def SetRigidBodyModels(parmDict,sigDict,rigidbodyDict,pFile=None):
1088    'needs a doc string'
1089   
1090    def PrintRBVectandSig(VectRB,VectSig):
1091        pFile.write('\n Rigid body vector magnitudes for %s:\n'%VectRB['RBname'])
1092        namstr = '  names :'
1093        valstr = '  values:'
1094        sigstr = '  esds  :'
1095        for i,[val,sig] in enumerate(zip(VectRB['VectMag'],VectSig)):
1096            namstr += '%12s'%('Vect '+str(i))
1097            valstr += '%12.4f'%(val)
1098            if sig:
1099                sigstr += '%12.4f'%(sig)
1100            else:
1101                sigstr += 12*' '
1102        pFile.write(namstr+'\n')
1103        pFile.write(valstr+'\n')
1104        pFile.write(sigstr+'\n')       
1105       
1106    RBIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})  #these are lists of rbIds
1107    if not RBIds['Vector']:
1108        return
1109    for irb,item in enumerate(RBIds['Vector']):
1110        if rigidbodyDict['Vector'][item]['useCount']:
1111            VectSig = []
1112            RBmags = rigidbodyDict['Vector'][item]['VectMag']
1113            for i,mag in enumerate(RBmags):
1114                name = '::RBV;'+str(i)+':'+str(irb)
1115                if name in sigDict:
1116                    VectSig.append(sigDict[name])
1117            PrintRBVectandSig(rigidbodyDict['Vector'][item],VectSig)   
1118       
1119################################################################################
1120##### Phase data
1121################################################################################                   
1122def GetPhaseData(PhaseData,RestraintDict={},rbIds={},Print=True,pFile=None,seqRef=False):
1123    '''Setup the phase information for a structural refinement, used for
1124    regular and sequential refinements, optionally printing information
1125    to the .lst file (if Print is True)
1126    '''
1127           
1128    def PrintFFtable(FFtable):
1129        pFile.write('\n X-ray scattering factors:\n')
1130        pFile.write('   Symbol     fa                                      fb                                      fc\n')
1131        pFile.write(99*'-'+'\n')
1132        for Ename in FFtable:
1133            ffdata = FFtable[Ename]
1134            fa = ffdata['fa']
1135            fb = ffdata['fb']
1136            pFile.write(' %8s %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f\n'%
1137                (Ename.ljust(8),fa[0],fa[1],fa[2],fa[3],fb[0],fb[1],fb[2],fb[3],ffdata['fc']))
1138               
1139    def PrintMFtable(MFtable):
1140        pFile.write('\n <j0> Magnetic scattering factors:\n')
1141        pFile.write('   Symbol     mfa                                    mfb                                     mfc\n')
1142        pFile.write(99*'-'+'\n')
1143        for Ename in MFtable:
1144            mfdata = MFtable[Ename]
1145            fa = mfdata['mfa']
1146            fb = mfdata['mfb']
1147            pFile.write(' %8s %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f\n'%
1148                (Ename.ljust(8),fa[0],fa[1],fa[2],fa[3],fb[0],fb[1],fb[2],fb[3],mfdata['mfc']))
1149        pFile.write('\n <j2> Magnetic scattering factors:\n')
1150        pFile.write('   Symbol     nfa                                    nfb                                     nfc\n')
1151        pFile.write(99*'-'+'\n')
1152        for Ename in MFtable:
1153            mfdata = MFtable[Ename]
1154            fa = mfdata['nfa']
1155            fb = mfdata['nfb']
1156            pFile.write(' %8s %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f\n'%
1157                (Ename.ljust(8),fa[0],fa[1],fa[2],fa[3],fb[0],fb[1],fb[2],fb[3],mfdata['nfc']))
1158               
1159    def PrintBLtable(BLtable):
1160        pFile.write('\n Neutron scattering factors:\n')
1161        pFile.write('   Symbol   isotope       mass       b       resonant terms\n')
1162        pFile.write(99*'-'+'\n')
1163        for Ename in BLtable:
1164            bldata = BLtable[Ename]
1165            isotope = bldata[0]
1166            mass = bldata[1]['Mass']
1167            if 'BW-LS' in bldata[1]:
1168                bres = bldata[1]['BW-LS']
1169                blen = 0
1170            else:
1171                blen = bldata[1]['SL'][0]
1172                bres = []
1173            line = ' %8s%11s %10.3f %8.3f'%(Ename.ljust(8),isotope.center(11),mass,blen)
1174            for item in bres:
1175                line += '%10.5g'%(item)
1176            pFile.write(line+'\n')
1177           
1178    def PrintRBObjects(resRBData,vecRBData):
1179       
1180        def PrintRBThermals():
1181            tlstr = ['11','22','33','12','13','23']
1182            sstr = ['12','13','21','23','31','32','AA','BB']
1183            TLS = RB['ThermalMotion'][1]
1184            TLSvar = RB['ThermalMotion'][2]
1185            if 'T' in RB['ThermalMotion'][0]:
1186                pFile.write('TLS data\n')
1187                text = ''
1188                for i in range(6):
1189                    text += 'T'+tlstr[i]+' %8.4f %s '%(TLS[i],str(TLSvar[i])[0])
1190                pFile.write(text+'\n')
1191                if 'L' in RB['ThermalMotion'][0]: 
1192                    text = ''
1193                    for i in range(6,12):
1194                        text += 'L'+tlstr[i-6]+' %8.2f %s '%(TLS[i],str(TLSvar[i])[0])
1195                    pFile.write(text+'\n')
1196                if 'S' in RB['ThermalMotion'][0]:
1197                    text = ''
1198                    for i in range(12,20):
1199                        text += 'S'+sstr[i-12]+' %8.3f %s '%(TLS[i],str(TLSvar[i])[0])
1200                    pFile.write(text+'\n')
1201            if 'U' in RB['ThermalMotion'][0]:
1202                pFile.write('Uiso data\n')
1203                text = 'Uiso'+' %10.3f %s'%(TLS[0],str(TLSvar[0])[0])           
1204                pFile.write(text+'\n')
1205           
1206        if len(resRBData):
1207            for RB in resRBData:
1208                Oxyz = RB['Orig'][0]
1209                Qrijk = RB['Orient'][0]
1210                Angle = 2.0*acosd(Qrijk[0])
1211                pFile.write('\nRBObject %s at %10.4f %10.4f %10.4f Refine? %s\n'%
1212                    (RB['RBname'],Oxyz[0],Oxyz[1],Oxyz[2],RB['Orig'][1]))
1213                pFile.write('Orientation angle,vector: %10.3f %10.4f %10.4f %10.4f Refine? %s\n'%
1214                    (Angle,Qrijk[1],Qrijk[2],Qrijk[3],RB['Orient'][1]))
1215                Torsions = RB['Torsions']
1216                if len(Torsions):
1217                    text = 'Torsions: '
1218                    for torsion in Torsions:
1219                        text += '%10.4f Refine? %s'%(torsion[0],torsion[1])
1220                    pFile.write(text+'\n')
1221                PrintRBThermals()
1222        if len(vecRBData):
1223            for RB in vecRBData:
1224                Oxyz = RB['Orig'][0]
1225                Qrijk = RB['Orient'][0]
1226                Angle = 2.0*acosd(Qrijk[0])
1227                pFile.write('\nRBObject %s at %10.4f %10.4f %10.4f Refine? %s\n'%
1228                    (RB['RBname'],Oxyz[0],Oxyz[1],Oxyz[2],RB['Orig'][1]))
1229                pFile.write('Orientation angle,vector: %10.3f %10.4f %10.4f %10.4f Refine? %s\n'%
1230                    (Angle,Qrijk[1],Qrijk[2],Qrijk[3],RB['Orient'][1]))
1231                PrintRBThermals()
1232               
1233    def PrintAtoms(General,Atoms):
1234        cx,ct,cs,cia = General['AtomPtrs']
1235        pFile.write('\n Atoms:\n')
1236        line = '   name    type  refine?   x         y         z    '+ \
1237            '  frac site sym  mult I/A   Uiso     U11     U22     U33     U12     U13     U23'
1238        if General['Type'] == 'macromolecular':
1239            line = ' res no residue chain'+line
1240        pFile.write(line+'\n')
1241        if General['Type'] in ['nuclear','magnetic','faulted',]:
1242            pFile.write(135*'-'+'\n')
1243            for i,at in enumerate(Atoms):
1244                line = '%7s'%(at[ct-1])+'%7s'%(at[ct])+'%7s'%(at[ct+1])+'%10.5f'%(at[cx])+'%10.5f'%(at[cx+1])+ \
1245                    '%10.5f'%(at[cx+2])+'%8.3f'%(at[cx+3])+'%7s'%(at[cs])+'%5d'%(at[cs+1])+'%5s'%(at[cia])
1246                if at[cia] == 'I':
1247                    line += '%8.5f'%(at[cia+1])+48*' '
1248                else:
1249                    line += 8*' '
1250                    for j in range(6):
1251                        line += '%8.5f'%(at[cia+2+j])
1252                pFile.write(line+'\n')
1253        elif General['Type'] == 'macromolecular':
1254            pFile.write(135*'-'+'\n')           
1255            for i,at in enumerate(Atoms):
1256                line = '%7s'%(at[0])+'%7s'%(at[1])+'%7s'%(at[2])+'%7s'%(at[ct-1])+'%7s'%(at[ct])+'%7s'%(at[ct+1])+'%10.5f'%(at[cx])+'%10.5f'%(at[cx+1])+ \
1257                    '%10.5f'%(at[cx+2])+'%8.3f'%(at[cx+3])+'%7s'%(at[cs])+'%5d'%(at[cs+1])+'%5s'%(at[cia])
1258                if at[cia] == 'I':
1259                    line += '%8.4f'%(at[cia+1])+48*' '
1260                else:
1261                    line += 8*' '
1262                    for j in range(6):
1263                        line += '%8.4f'%(at[cia+2+j])
1264                pFile.write(line+'\n')
1265               
1266    def PrintMoments(General,Atoms):
1267        cx,ct,cs,cia = General['AtomPtrs']
1268        cmx = cx+4
1269        AtInfo = dict(zip(General['AtomTypes'],General['Lande g']))
1270        pFile.write('\n Magnetic moments:\n')
1271        line = '   name    type  refine?  Mx        My        Mz    '
1272        pFile.write(line+'\n')
1273        pFile.write(135*'-'+'\n')
1274        for i,at in enumerate(Atoms):
1275            if AtInfo[at[ct]]:
1276                line = '%7s'%(at[ct-1])+'%7s'%(at[ct])+'%7s'%(at[ct+1])+'%10.5f'%(at[cmx])+'%10.5f'%(at[cmx+1])+ \
1277                    '%10.5f'%(at[cmx+2])
1278                pFile.write(line+'\n')
1279       
1280               
1281    def PrintWaves(General,Atoms):
1282        cx,ct,cs,cia = General['AtomPtrs']
1283        pFile.write('\n Modulation waves\n')
1284        names = {'Sfrac':['Fsin','Fcos','Fzero','Fwid'],'Spos':['Xsin','Ysin','Zsin','Xcos','Ycos','Zcos','Tmin','Tmax','Xmax','Ymax','Zmax'],
1285            'Sadp':['U11sin','U22sin','U33sin','U12sin','U13sin','U23sin','U11cos','U22cos',
1286            'U33cos','U12cos','U13cos','U23cos'],'Smag':['MXsin','MYsin','MZsin','MXcos','MYcos','MZcos']}
1287        pFile.write(135*'-'+'\n')
1288        for i,at in enumerate(Atoms):
1289            AtomSS = at[-1]['SS1']
1290            for Stype in ['Sfrac','Spos','Sadp','Smag']:
1291                Waves = AtomSS[Stype]
1292                if len(Waves):
1293                    pFile.write(' atom: %s, site sym: %s, type: %s wave type: %s:\n'%
1294                        (at[ct-1],at[cs],Stype,Waves[0]))
1295                else:
1296                    continue
1297                for iw,wave in enumerate(Waves[1:]):                   
1298                    line = ''
1299                    if Waves[0] in ['Block','ZigZag'] and Stype == 'Spos' and not iw:
1300                        for item in names[Stype][6:]:
1301                            line += '%8s '%(item)                       
1302                    else:
1303                        if Stype == 'Spos':
1304                            for item in names[Stype][:6]:
1305                                line += '%8s '%(item)
1306                        else:
1307                            for item in names[Stype]:
1308                                line += '%8s '%(item)
1309                    pFile.write(line+'\n')
1310                    line = ''
1311                    for item in wave[0]:
1312                        line += '%8.4f '%(item)
1313                    line += ' Refine? '+str(wave[1])
1314                    pFile.write(line+'\n')
1315       
1316    def PrintTexture(textureData):
1317        topstr = '\n Spherical harmonics texture: Order:' + \
1318            str(textureData['Order'])
1319        if textureData['Order']:
1320            pFile.write('%s Refine? %s\n'%(topstr,textureData['SH Coeff'][0]))
1321        else:
1322            pFile.write(topstr+'\n')
1323            return
1324        names = ['omega','chi','phi']
1325        line = '\n'
1326        for name in names:
1327            line += ' SH '+name+':'+'%12.4f'%(textureData['Sample '+name][1])+' Refine? '+str(textureData['Sample '+name][0])
1328        pFile.write(line+'\n')
1329        pFile.write('\n Texture coefficients:\n')
1330        SHcoeff = textureData['SH Coeff'][1]
1331        SHkeys = list(SHcoeff.keys())
1332        nCoeff = len(SHcoeff)
1333        nBlock = nCoeff//10+1
1334        iBeg = 0
1335        iFin = min(iBeg+10,nCoeff)
1336        for block in range(nBlock):
1337            ptlbls = ' names :'
1338            ptstr =  ' values:'
1339            for item in SHkeys[iBeg:iFin]:
1340                ptlbls += '%12s'%(item)
1341                ptstr += '%12.4f'%(SHcoeff[item]) 
1342            pFile.write(ptlbls+'\n')
1343            pFile.write(ptstr+'\n')
1344            iBeg += 10
1345            iFin = min(iBeg+10,nCoeff)
1346       
1347    def MakeRBParms(rbKey,phaseVary,phaseDict):
1348        rbid = str(rbids.index(RB['RBId']))
1349        pfxRB = pfx+'RB'+rbKey+'P'
1350        pstr = ['x','y','z']
1351        ostr = ['a','i','j','k']
1352        for i in range(3):
1353            name = pfxRB+pstr[i]+':'+str(iRB)+':'+rbid
1354            phaseDict[name] = RB['Orig'][0][i]
1355            if RB['Orig'][1]:
1356                phaseVary += [name,]
1357        pfxRB = pfx+'RB'+rbKey+'O'
1358        for i in range(4):
1359            name = pfxRB+ostr[i]+':'+str(iRB)+':'+rbid
1360            phaseDict[name] = RB['Orient'][0][i]
1361            if RB['Orient'][1] == 'AV' and i:
1362                phaseVary += [name,]
1363            elif RB['Orient'][1] == 'A' and not i:
1364                phaseVary += [name,]
1365           
1366    def MakeRBThermals(rbKey,phaseVary,phaseDict):
1367        rbid = str(rbids.index(RB['RBId']))
1368        tlstr = ['11','22','33','12','13','23']
1369        sstr = ['12','13','21','23','31','32','AA','BB']
1370        if 'T' in RB['ThermalMotion'][0]:
1371            pfxRB = pfx+'RB'+rbKey+'T'
1372            for i in range(6):
1373                name = pfxRB+tlstr[i]+':'+str(iRB)+':'+rbid
1374                phaseDict[name] = RB['ThermalMotion'][1][i]
1375                if RB['ThermalMotion'][2][i]:
1376                    phaseVary += [name,]
1377        if 'L' in RB['ThermalMotion'][0]:
1378            pfxRB = pfx+'RB'+rbKey+'L'
1379            for i in range(6):
1380                name = pfxRB+tlstr[i]+':'+str(iRB)+':'+rbid
1381                phaseDict[name] = RB['ThermalMotion'][1][i+6]
1382                if RB['ThermalMotion'][2][i+6]:
1383                    phaseVary += [name,]
1384        if 'S' in RB['ThermalMotion'][0]:
1385            pfxRB = pfx+'RB'+rbKey+'S'
1386            for i in range(8):
1387                name = pfxRB+sstr[i]+':'+str(iRB)+':'+rbid
1388                phaseDict[name] = RB['ThermalMotion'][1][i+12]
1389                if RB['ThermalMotion'][2][i+12]:
1390                    phaseVary += [name,]
1391        if 'U' in RB['ThermalMotion'][0]:
1392            name = pfx+'RB'+rbKey+'U:'+str(iRB)+':'+rbid
1393            phaseDict[name] = RB['ThermalMotion'][1][0]
1394            if RB['ThermalMotion'][2][0]:
1395                phaseVary += [name,]
1396               
1397    def MakeRBTorsions(rbKey,phaseVary,phaseDict):
1398        rbid = str(rbids.index(RB['RBId']))
1399        pfxRB = pfx+'RB'+rbKey+'Tr;'
1400        for i,torsion in enumerate(RB['Torsions']):
1401            name = pfxRB+str(i)+':'+str(iRB)+':'+rbid
1402            phaseDict[name] = torsion[0]
1403            if torsion[1]:
1404                phaseVary += [name,]
1405                   
1406    if Print:
1407        pFile.write('\n Phases:\n')
1408    phaseVary = []
1409    phaseDict = {}
1410    pawleyLookup = {}
1411    FFtables = {}                   #scattering factors - xrays
1412    MFtables = {}                   #Mag. form factors
1413    BLtables = {}                   # neutrons
1414    Natoms = {}
1415    maxSSwave = {}
1416    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
1417    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
1418    atomIndx = {}
1419    for name in PhaseData:
1420        General = PhaseData[name]['General']
1421        pId = PhaseData[name]['pId']
1422        pfx = str(pId)+'::'
1423        FFtable = G2el.GetFFtable(General['AtomTypes'])
1424        BLtable = G2el.GetBLtable(General)
1425        FFtables.update(FFtable)
1426        BLtables.update(BLtable)
1427        phaseDict[pfx+'isMag'] = False
1428        SGData = General['SGData']
1429        SGtext,SGtable = G2spc.SGPrint(SGData)
1430        if General['Type'] == 'magnetic':
1431            MFtable = G2el.GetMFtable(General['AtomTypes'],General['Lande g'])
1432            MFtables.update(MFtable)
1433            phaseDict[pfx+'isMag'] = True
1434            SpnFlp = SGData['SpnFlp']
1435        Atoms = PhaseData[name]['Atoms']
1436        if Atoms and not General.get('doPawley'):
1437            cx,ct,cs,cia = General['AtomPtrs']
1438            AtLookup = G2mth.FillAtomLookUp(Atoms,cia+8)
1439        PawleyRef = PhaseData[name].get('Pawley ref',[])
1440        cell = General['Cell']
1441        A = G2lat.cell2A(cell[1:7])
1442        phaseDict.update({pfx+'A0':A[0],pfx+'A1':A[1],pfx+'A2':A[2],
1443            pfx+'A3':A[3],pfx+'A4':A[4],pfx+'A5':A[5],pfx+'Vol':G2lat.calc_V(A)})
1444        if cell[0]:
1445            phaseVary += cellVary(pfx,SGData)       #also fills in symmetry required constraints
1446        SSGtext = []    #no superstructure
1447        im = 0
1448        if General.get('Modulated',False):
1449            im = 1      #refl offset
1450            Vec,vRef,maxH = General['SuperVec']
1451            phaseDict.update({pfx+'mV0':Vec[0],pfx+'mV1':Vec[1],pfx+'mV2':Vec[2]})
1452            SSGData = General['SSGData']
1453            SSGtext,SSGtable = G2spc.SSGPrint(SGData,SSGData)
1454            if vRef:
1455                phaseVary += modVary(pfx,SSGData)       
1456        resRBData = PhaseData[name]['RBModels'].get('Residue',[])
1457        if resRBData:
1458            rbids = rbIds['Residue']    #NB: used in the MakeRB routines
1459            for iRB,RB in enumerate(resRBData):
1460                MakeRBParms('R',phaseVary,phaseDict)
1461                MakeRBThermals('R',phaseVary,phaseDict)
1462                MakeRBTorsions('R',phaseVary,phaseDict)
1463       
1464        vecRBData = PhaseData[name]['RBModels'].get('Vector',[])
1465        if vecRBData:
1466            rbids = rbIds['Vector']    #NB: used in the MakeRB routines
1467            for iRB,RB in enumerate(vecRBData):
1468                MakeRBParms('V',phaseVary,phaseDict)
1469                MakeRBThermals('V',phaseVary,phaseDict)
1470                   
1471        Natoms[pfx] = 0
1472        maxSSwave[pfx] = {'Sfrac':0,'Spos':0,'Sadp':0,'Smag':0}
1473        if Atoms and not General.get('doPawley'):
1474            cx,ct,cs,cia = General['AtomPtrs']
1475            Natoms[pfx] = len(Atoms)
1476            for i,at in enumerate(Atoms):
1477                atomIndx[at[cia+8]] = [pfx,i]      #lookup table for restraints
1478                phaseDict.update({pfx+'Atype:'+str(i):at[ct],pfx+'Afrac:'+str(i):at[cx+3],pfx+'Amul:'+str(i):at[cs+1],
1479                    pfx+'Ax:'+str(i):at[cx],pfx+'Ay:'+str(i):at[cx+1],pfx+'Az:'+str(i):at[cx+2],
1480                    pfx+'dAx:'+str(i):0.,pfx+'dAy:'+str(i):0.,pfx+'dAz:'+str(i):0.,         #refined shifts for x,y,z
1481                    pfx+'AI/A:'+str(i):at[cia],})
1482                if at[cia] == 'I':
1483                    phaseDict[pfx+'AUiso:'+str(i)] = at[cia+1]
1484                else:
1485                    phaseDict.update({pfx+'AU11:'+str(i):at[cia+2],pfx+'AU22:'+str(i):at[cia+3],pfx+'AU33:'+str(i):at[cia+4],
1486                        pfx+'AU12:'+str(i):at[cia+5],pfx+'AU13:'+str(i):at[cia+6],pfx+'AU23:'+str(i):at[cia+7]})
1487                if General['Type'] == 'magnetic':
1488                    phaseDict.update({pfx+'AMx:'+str(i):at[cx+4],pfx+'AMy:'+str(i):at[cx+5],pfx+'AMz:'+str(i):at[cx+6]})
1489                if 'F' in at[ct+1]:
1490                    phaseVary.append(pfx+'Afrac:'+str(i))
1491                if 'X' in at[ct+1]:
1492                    try:    #patch for sytsym name changes
1493                        xId,xCoef = G2spc.GetCSxinel(at[cs])
1494                    except KeyError:
1495                        Sytsym = G2spc.SytSym(at[cx:cx+3],SGData)[0]
1496                        at[cs] = Sytsym
1497                        xId,xCoef = G2spc.GetCSxinel(at[cs])
1498                    names = [pfx+'dAx:'+str(i),pfx+'dAy:'+str(i),pfx+'dAz:'+str(i)]
1499                    equivs = [[],[],[]]
1500                    for j in range(3):
1501                        if xId[j] > 0:                               
1502                            phaseVary.append(names[j])
1503                            equivs[xId[j]-1].append([names[j],xCoef[j]])
1504                    for equiv in equivs:
1505                        if len(equiv) > 1:
1506                            name = equiv[0][0]
1507                            coef = equiv[0][1]
1508                            for eqv in equiv[1:]:
1509                                eqv[1] /= coef
1510                                G2mv.StoreEquivalence(name,(eqv,))
1511                if 'U' in at[ct+1]:
1512                    if at[cia] == 'I':
1513                        phaseVary.append(pfx+'AUiso:'+str(i))
1514                    else:
1515                        try:    #patch for sytsym name changes
1516                            uId,uCoef = G2spc.GetCSuinel(at[cs])[:2]
1517                        except KeyError:
1518                            Sytsym = G2spc.SytSym(at[cx:cx+3],SGData)[0]
1519                            at[cs] = Sytsym
1520                            uId,uCoef = G2spc.GetCSuinel(at[cs])[:2]
1521                        names = [pfx+'AU11:'+str(i),pfx+'AU22:'+str(i),pfx+'AU33:'+str(i),
1522                            pfx+'AU12:'+str(i),pfx+'AU13:'+str(i),pfx+'AU23:'+str(i)]
1523                        equivs = [[],[],[],[],[],[]]
1524                        for j in range(6):
1525                            if uId[j] > 0:                               
1526                                phaseVary.append(names[j])
1527                                equivs[uId[j]-1].append([names[j],uCoef[j]])
1528                        for equiv in equivs:
1529                            if len(equiv) > 1:
1530                                name = equiv[0][0]
1531                                coef = equiv[0][1]
1532                                for eqv in equiv[1:]:
1533                                    eqv[1] /= coef
1534                                    G2mv.StoreEquivalence(name,(eqv,))
1535                if 'M' in at[ct+1]:
1536                    SytSym,Mul,Nop,dupDir = G2spc.SytSym(at[cx:cx+3],SGData)
1537                    mId,mCoef = G2spc.GetCSpqinel(SpnFlp,dupDir)
1538                    names = [pfx+'AMx:'+str(i),pfx+'AMy:'+str(i),pfx+'AMz:'+str(i)]
1539                    equivs = [[],[],[]]
1540                    for j in range(3):
1541                        if mId[j] > 0:
1542                            phaseVary.append(names[j])
1543                            equivs[mId[j]-1].append([names[j],mCoef[j]])
1544                    for equiv in equivs:
1545                        if len(equiv) > 1:
1546                            name = equiv[0][0]
1547                            coef = equiv[0][1]
1548                            for eqv in equiv[1:]:
1549                                eqv[1] /= coef
1550                                G2mv.StoreEquivalence(name,(eqv,))
1551                if General.get('Modulated',False):
1552                    AtomSS = at[-1]['SS1']
1553                    for Stype in ['Sfrac','Spos','Sadp','Smag']:
1554                        Waves = AtomSS[Stype]
1555                        if len(Waves):
1556                            waveType = Waves[0]
1557                        else:
1558                            continue
1559                        phaseDict[pfx+Stype[1].upper()+'waveType:'+str(i)] = waveType
1560                        nx = 0
1561                        for iw,wave in enumerate(Waves[1:]):
1562                            if not iw:
1563                                if waveType in ['ZigZag','Block']:
1564                                    nx = 1
1565                                CSI = G2spc.GetSSfxuinel(waveType,Stype,1,at[cx:cx+3],SGData,SSGData)
1566                            else:
1567                                CSI = G2spc.GetSSfxuinel('Fourier',Stype,iw+1-nx,at[cx:cx+3],SGData,SSGData)
1568                            uId,uCoef = CSI[0]
1569                            stiw = str(i)+':'+str(iw)
1570                            if Stype == 'Spos':
1571                                if waveType in ['ZigZag','Block',] and not iw:
1572                                    names = [pfx+'Tmin:'+stiw,pfx+'Tmax:'+stiw,pfx+'Xmax:'+stiw,pfx+'Ymax:'+stiw,pfx+'Zmax:'+stiw]
1573                                    equivs = [[],[], [],[],[]]
1574                                else:
1575                                    names = [pfx+'Xsin:'+stiw,pfx+'Ysin:'+stiw,pfx+'Zsin:'+stiw,
1576                                        pfx+'Xcos:'+stiw,pfx+'Ycos:'+stiw,pfx+'Zcos:'+stiw]
1577                                    equivs = [[],[],[], [],[],[]]
1578                            elif Stype == 'Sadp':
1579                                names = [pfx+'U11sin:'+stiw,pfx+'U22sin:'+stiw,pfx+'U33sin:'+stiw,
1580                                    pfx+'U12sin:'+stiw,pfx+'U13sin:'+stiw,pfx+'U23sin:'+stiw,
1581                                    pfx+'U11cos:'+stiw,pfx+'U22cos:'+stiw,pfx+'U33cos:'+stiw,
1582                                    pfx+'U12cos:'+stiw,pfx+'U13cos:'+stiw,pfx+'U23cos:'+stiw]
1583                                equivs = [[],[],[],[],[],[], [],[],[],[],[],[]]
1584                            elif Stype == 'Sfrac':
1585                                equivs = [[],[]]
1586                                if 'Crenel' in waveType and not iw:
1587                                    names = [pfx+'Fzero:'+stiw,pfx+'Fwid:'+stiw]
1588                                else:
1589                                    names = [pfx+'Fsin:'+stiw,pfx+'Fcos:'+stiw]
1590                            elif Stype == 'Smag':
1591                                equivs = [[],[],[], [],[],[]]
1592                                names = [pfx+'MXsin:'+stiw,pfx+'MYsin:'+stiw,pfx+'MZsin:'+stiw,
1593                                    pfx+'MXcos:'+stiw,pfx+'MYcos:'+stiw,pfx+'MZcos:'+stiw]
1594                            phaseDict.update(dict(zip(names,wave[0])))
1595                            if wave[1]: #what do we do here for multiple terms in modulation constraints?
1596                                for j in range(len(equivs)):
1597                                    if uId[j][0] > 0:                               
1598                                        phaseVary.append(names[j])
1599                                        equivs[uId[j][0]-1].append([names[j],uCoef[j][0]])
1600                                for equiv in equivs:
1601                                    if len(equiv) > 1:
1602                                        name = equiv[0][0]
1603                                        coef = equiv[0][1]
1604                                        for eqv in equiv[1:]:
1605                                            eqv[1] /= coef
1606                                            G2mv.StoreEquivalence(name,(eqv,))
1607                            maxSSwave[pfx][Stype] = max(maxSSwave[pfx][Stype],iw+1)
1608            textureData = General['SH Texture']
1609            if textureData['Order'] and not seqRef:
1610                phaseDict[pfx+'SHorder'] = textureData['Order']
1611                phaseDict[pfx+'SHmodel'] = SamSym[textureData['Model']]
1612                for item in ['omega','chi','phi']:
1613                    phaseDict[pfx+'SH '+item] = textureData['Sample '+item][1]
1614                    if textureData['Sample '+item][0]:
1615                        phaseVary.append(pfx+'SH '+item)
1616                for item in textureData['SH Coeff'][1]:
1617                    phaseDict[pfx+item] = textureData['SH Coeff'][1][item]
1618                    if textureData['SH Coeff'][0]:
1619                        phaseVary.append(pfx+item)
1620               
1621            if Print:
1622                pFile.write('\n Phase name: %s\n'%General['Name'])
1623                pFile.write(135*'='+'\n')
1624                PrintFFtable(FFtable)
1625                PrintBLtable(BLtable)
1626                if General['Type'] == 'magnetic':
1627                    PrintMFtable(MFtable)
1628                pFile.write('\n')
1629                #how do we print magnetic symmetry table? TBD
1630                if len(SSGtext):    #if superstructure
1631                    for line in SSGtext: pFile.write(line+'\n')
1632                    if len(SSGtable):
1633                        for item in SSGtable:
1634                            line = ' %s '%(item)
1635                            pFile.write(line+'\n') 
1636                    else:
1637                        pFile.write(' ( 1)    %s\n'%(SSGtable[0]))
1638                else:
1639                    for line in SGtext: pFile.write(line+'\n')
1640                    if len(SGtable):
1641                        for item in SGtable:
1642                            line = ' %s '%(item)
1643                            pFile.write(line+'\n') 
1644                    else:
1645                        pFile.write(' ( 1)    %s\n'%(SGtable[0]))
1646                PrintRBObjects(resRBData,vecRBData)
1647                PrintAtoms(General,Atoms)
1648                if General['Type'] == 'magnetic':
1649                    PrintMoments(General,Atoms)
1650                if General.get('Modulated',False):
1651                    PrintWaves(General,Atoms)
1652                pFile.write('\n Unit cell: a = %.5f b = %.5f c = %.5f alpha = %.3f beta = %.3f gamma = %.3f volume = %.3f Refine? %s\n'%
1653                    (cell[1],cell[2],cell[3],cell[4],cell[5],cell[6],cell[7],cell[0]))
1654                if len(SSGtext):    #if superstructure
1655                    pFile.write('\n Modulation vector: mV0 = %.4f mV1 = %.4f mV2 = %.4f max mod. index = %d Refine? %s\n'%
1656                        (Vec[0],Vec[1],Vec[2],maxH,vRef))
1657                if not seqRef:
1658                    PrintTexture(textureData)
1659                if name in RestraintDict:
1660                    PrintRestraints(cell[1:7],SGData,General['AtomPtrs'],Atoms,AtLookup,
1661                        textureData,RestraintDict[name],pFile)
1662                   
1663        elif PawleyRef:
1664            if Print:
1665                pFile.write('\n Phase name: %s\n'%General['Name'])
1666                pFile.write(135*'='+'\n')
1667                pFile.write('\n')
1668                if len(SSGtext):    #if superstructure
1669                    for line in SSGtext: pFile.write(line+'\n')
1670                    if len(SSGtable):
1671                        for item in SSGtable:
1672                            line = ' %s '%(item)
1673                            pFile.write(line+'\n') 
1674                    else:
1675                        pFile.write(' ( 1)    %s\n'%SSGtable[0])
1676                else:
1677                    for line in SGtext: pFile.write(line+'\n')
1678                    if len(SGtable):
1679                        for item in SGtable:
1680                            line = ' %s '%(item)
1681                            pFile.write(line+'\n')
1682                    else:
1683                        pFile.write(' ( 1)    %s\n'%(SGtable[0]))
1684                pFile.write('\n Unit cell: a = %.5f b = %.5f c = %.5f alpha = %.3f beta = %.3f gamma = %.3f volume = %.3f Refine? %s\n'%
1685                    (cell[1],cell[2],cell[3],cell[4],cell[5],cell[6],cell[7],cell[0]))
1686                if len(SSGtext):    #if superstructure
1687                    pFile.write('\n Modulation vector: mV0 = %.4f mV1 = %.4f mV2 = %.4f max mod. index = %d Refine? %s\n'%
1688                        (Vec[0],Vec[1],Vec[2],maxH,vRef))
1689            pawleyVary = []
1690            for i,refl in enumerate(PawleyRef):
1691                phaseDict[pfx+'PWLref:'+str(i)] = refl[6+im]
1692                if im:
1693                    pawleyLookup[pfx+'%d,%d,%d,%d'%(refl[0],refl[1],refl[2],refl[3])] = i
1694                else:
1695                    pawleyLookup[pfx+'%d,%d,%d'%(refl[0],refl[1],refl[2])] = i
1696                if refl[5+im]:
1697                    pawleyVary.append(pfx+'PWLref:'+str(i))
1698            GetPawleyConstr(SGData['SGLaue'],PawleyRef,im,pawleyVary)      #does G2mv.StoreEquivalence
1699            phaseVary += pawleyVary
1700               
1701    return Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,MFtables,maxSSwave
1702   
1703def cellFill(pfx,SGData,parmDict,sigDict): 
1704    '''Returns the filled-out reciprocal cell (A) terms and their uncertainties
1705    from the parameter and sig dictionaries.
1706
1707    :param str pfx: parameter prefix ("n::", where n is a phase number)
1708    :param dict SGdata: a symmetry object
1709    :param dict parmDict: a dictionary of parameters
1710    :param dict sigDict:  a dictionary of uncertainties on parameters
1711
1712    :returns: A,sigA where each is a list of six terms with the A terms
1713    '''
1714    if SGData['SGLaue'] in ['-1',]:
1715        A = [parmDict[pfx+'A0'],parmDict[pfx+'A1'],parmDict[pfx+'A2'],
1716            parmDict[pfx+'A3'],parmDict[pfx+'A4'],parmDict[pfx+'A5']]
1717    elif SGData['SGLaue'] in ['2/m',]:
1718        if SGData['SGUniq'] == 'a':
1719            A = [parmDict[pfx+'A0'],parmDict[pfx+'A1'],parmDict[pfx+'A2'],
1720                0,0,parmDict[pfx+'A5']]
1721        elif SGData['SGUniq'] == 'b':
1722            A = [parmDict[pfx+'A0'],parmDict[pfx+'A1'],parmDict[pfx+'A2'],
1723                0,parmDict[pfx+'A4'],0]
1724        else:
1725            A = [parmDict[pfx+'A0'],parmDict[pfx+'A1'],parmDict[pfx+'A2'],
1726                parmDict[pfx+'A3'],0,0]
1727    elif SGData['SGLaue'] in ['mmm',]:
1728        A = [parmDict[pfx+'A0'],parmDict[pfx+'A1'],parmDict[pfx+'A2'],0,0,0]
1729    elif SGData['SGLaue'] in ['4/m','4/mmm']:
1730        A = [parmDict[pfx+'A0'],parmDict[pfx+'A0'],parmDict[pfx+'A2'],0,0,0]
1731    elif SGData['SGLaue'] in ['6/m','6/mmm','3m1', '31m', '3']:
1732        A = [parmDict[pfx+'A0'],parmDict[pfx+'A0'],parmDict[pfx+'A2'],
1733            parmDict[pfx+'A0'],0,0]
1734    elif SGData['SGLaue'] in ['3R', '3mR']:
1735        A = [parmDict[pfx+'A0'],parmDict[pfx+'A0'],parmDict[pfx+'A0'],
1736            parmDict[pfx+'A3'],parmDict[pfx+'A3'],parmDict[pfx+'A3']]
1737    elif SGData['SGLaue'] in ['m3m','m3']:
1738        A = [parmDict[pfx+'A0'],parmDict[pfx+'A0'],parmDict[pfx+'A0'],0,0,0]
1739
1740    try:
1741        if SGData['SGLaue'] in ['-1',]:
1742            sigA = [sigDict[pfx+'A0'],sigDict[pfx+'A1'],sigDict[pfx+'A2'],
1743                sigDict[pfx+'A3'],sigDict[pfx+'A4'],sigDict[pfx+'A5']]
1744        elif SGData['SGLaue'] in ['2/m',]:
1745            if SGData['SGUniq'] == 'a':
1746                sigA = [sigDict[pfx+'A0'],sigDict[pfx+'A1'],sigDict[pfx+'A2'],
1747                    0,0,sigDict[pfx+'A5']]
1748            elif SGData['SGUniq'] == 'b':
1749                sigA = [sigDict[pfx+'A0'],sigDict[pfx+'A1'],sigDict[pfx+'A2'],
1750                    0,sigDict[pfx+'A4'],0]
1751            else:
1752                sigA = [sigDict[pfx+'A0'],sigDict[pfx+'A1'],sigDict[pfx+'A2'],
1753                    sigDict[pfx+'A3'],0,0]
1754        elif SGData['SGLaue'] in ['mmm',]:
1755            sigA = [sigDict[pfx+'A0'],sigDict[pfx+'A1'],sigDict[pfx+'A2'],0,0,0]
1756        elif SGData['SGLaue'] in ['4/m','4/mmm']:
1757            sigA = [sigDict[pfx+'A0'],0,sigDict[pfx+'A2'],0,0,0]
1758        elif SGData['SGLaue'] in ['6/m','6/mmm','3m1', '31m', '3']:
1759            sigA = [sigDict[pfx+'A0'],0,sigDict[pfx+'A2'],0,0,0]
1760        elif SGData['SGLaue'] in ['3R', '3mR']:
1761            sigA = [sigDict[pfx+'A0'],0,0,sigDict[pfx+'A3'],0,0]
1762        elif SGData['SGLaue'] in ['m3m','m3']:
1763            sigA = [sigDict[pfx+'A0'],0,0,0,0,0]
1764    except KeyError:
1765        sigA = [0,0,0,0,0,0]
1766    return A,sigA
1767       
1768def PrintRestraints(cell,SGData,AtPtrs,Atoms,AtLookup,textureData,phaseRest,pFile):
1769    'needs a doc string'
1770    if phaseRest:
1771        Amat = G2lat.cell2AB(cell)[0]
1772        cx,ct,cs = AtPtrs[:3]
1773        names = [['Bond','Bonds'],['Angle','Angles'],['Plane','Planes'],
1774            ['Chiral','Volumes'],['Torsion','Torsions'],['Rama','Ramas'],
1775            ['ChemComp','Sites'],['Texture','HKLs']]
1776        for name,rest in names:
1777            itemRest = phaseRest[name]
1778            if rest in itemRest and itemRest[rest] and itemRest['Use']:
1779                pFile.write('\n  %s restraint weight factor %10.3f Use: %s\n'%(name,itemRest['wtFactor'],str(itemRest['Use'])))
1780                if name in ['Bond','Angle','Plane','Chiral']:
1781                    pFile.write('     calc       obs      sig   delt/sig  atoms(symOp): \n')
1782                    for indx,ops,obs,esd in itemRest[rest]:
1783                        try:
1784                            AtNames = G2mth.GetAtomItemsById(Atoms,AtLookup,indx,ct-1)
1785                            AtName = ''
1786                            for i,Aname in enumerate(AtNames):
1787                                AtName += Aname
1788                                if ops[i] == '1':
1789                                    AtName += '-'
1790                                else:
1791                                    AtName += '+('+ops[i]+')-'
1792                            XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cx,3))
1793                            XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
1794                            if name == 'Bond':
1795                                calc = G2mth.getRestDist(XYZ,Amat)
1796                            elif name == 'Angle':
1797                                calc = G2mth.getRestAngle(XYZ,Amat)
1798                            elif name == 'Plane':
1799                                calc = G2mth.getRestPlane(XYZ,Amat)
1800                            elif name == 'Chiral':
1801                                calc = G2mth.getRestChiral(XYZ,Amat)
1802                            pFile.write(' %9.3f %9.3f %8.3f %8.3f   %s\n'%(calc,obs,esd,(obs-calc)/esd,AtName[:-1]))
1803                        except KeyError:
1804                            del itemRest[rest]
1805                elif name in ['Torsion','Rama']:
1806                    pFile.write('  atoms(symOp)  calc  obs  sig  delt/sig  torsions: \n')
1807                    coeffDict = itemRest['Coeff']
1808                    for indx,ops,cofName,esd in itemRest[rest]:
1809                        AtNames = G2mth.GetAtomItemsById(Atoms,AtLookup,indx,ct-1)
1810                        AtName = ''
1811                        for i,Aname in enumerate(AtNames):
1812                            AtName += Aname+'+('+ops[i]+')-'
1813                        XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cx,3))
1814                        XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
1815                        if name == 'Torsion':
1816                            tor = G2mth.getRestTorsion(XYZ,Amat)
1817                            restr,calc = G2mth.calcTorsionEnergy(tor,coeffDict[cofName])
1818                            pFile.write(' %8.3f %8.3f %.3f %8.3f %8.3f %s\n'%(calc,obs,esd,(obs-calc)/esd,tor,AtName[:-1]))
1819                        else:
1820                            phi,psi = G2mth.getRestRama(XYZ,Amat)
1821                            restr,calc = G2mth.calcRamaEnergy(phi,psi,coeffDict[cofName])                               
1822                            pFile.write(' %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %s\n'%(calc,obs,esd,(obs-calc)/esd,phi,psi,AtName[:-1]))
1823                elif name == 'ChemComp':
1824                    pFile.write('     atoms   mul*frac  factor     prod\n')
1825                    for indx,factors,obs,esd in itemRest[rest]:
1826                        try:
1827                            atoms = G2mth.GetAtomItemsById(Atoms,AtLookup,indx,ct-1)
1828                            mul = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cs+1))
1829                            frac = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cs-1))
1830                            mulfrac = mul*frac
1831                            calcs = mul*frac*factors
1832                            for iatm,[atom,mf,fr,clc] in enumerate(zip(atoms,mulfrac,factors,calcs)):
1833                                pFile.write(' %10s %8.3f %8.3f %8.3f\n'%(atom,mf,fr,clc))
1834                            pFile.write(' Sum:                   calc: %8.3f obs: %8.3f esd: %8.3f\n'%(np.sum(calcs),obs,esd))
1835                        except KeyError:
1836                            del itemRest[rest]
1837                elif name == 'Texture' and textureData['Order']:
1838                    Start = False
1839                    SHCoef = textureData['SH Coeff'][1]
1840                    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
1841                    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
1842                    pFile.write ('    HKL  grid  neg esd  sum neg  num neg use unit?  unit esd \n')
1843                    for hkl,grid,esd1,ifesd2,esd2 in itemRest[rest]:
1844                        phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
1845                        ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1846                        R,P,Z = G2mth.getRestPolefig(ODFln,SamSym[textureData['Model']],grid)
1847                        Z = ma.masked_greater(Z,0.0)
1848                        num = ma.count(Z)
1849                        sum = 0
1850                        if num:
1851                            sum = np.sum(Z)
1852                        pFile.write ('   %d %d %d  %d %8.3f %8.3f %8d   %s    %8.3f\n'%(hkl[0],hkl[1],hkl[2],grid,esd1,sum,num,str(ifesd2),esd2))
1853       
1854def getCellEsd(pfx,SGData,A,covData):
1855    'needs a doc string'
1856    rVsq = G2lat.calc_rVsq(A)
1857    G,g = G2lat.A2Gmat(A)       #get recip. & real metric tensors
1858    RMnames = [pfx+'A0',pfx+'A1',pfx+'A2',pfx+'A3',pfx+'A4',pfx+'A5']
1859    varyList = covData['varyList']
1860    covMatrix = covData['covMatrix']
1861    if len(covMatrix):
1862        vcov = G2mth.getVCov(RMnames,varyList,covMatrix)
1863        if SGData['SGLaue'] in ['3', '3m1', '31m', '6/m', '6/mmm']:
1864            vcov[1,1] = vcov[3,3] = vcov[0,1] = vcov[1,0] = vcov[0,0]
1865            vcov[1,3] = vcov[3,1] = vcov[0,3] = vcov[3,0] = vcov[0,0]
1866            vcov[1,2] = vcov[2,1] = vcov[2,3] = vcov[3,2] = vcov[0,2]
1867        elif SGData['SGLaue'] in ['m3','m3m']:
1868            vcov[0:3,0:3] = vcov[0,0]
1869        elif SGData['SGLaue'] in ['4/m', '4/mmm']:
1870            vcov[0:2,0:2] = vcov[0,0]
1871            vcov[1,2] = vcov[2,1] = vcov[0,2]
1872        elif SGData['SGLaue'] in ['3R','3mR']:
1873            vcov[0:3,0:3] = vcov[0,0]
1874    #        vcov[4,4] = vcov[5,5] = vcov[3,3]
1875            vcov[3:6,3:6] = vcov[3,3]
1876            vcov[0:3,3:6] = vcov[0,3]
1877            vcov[3:6,0:3] = vcov[3,0]
1878    else:
1879        vcov = np.eye(6)
1880    delt = 1.e-9
1881    drVdA = np.zeros(6)
1882    for i in range(6):
1883        A[i] += delt
1884        drVdA[i] = G2lat.calc_rVsq(A)
1885        A[i] -= 2*delt
1886        drVdA[i] -= G2lat.calc_rVsq(A)
1887        A[i] += delt
1888    drVdA /= 2.*delt   
1889    srcvlsq = np.inner(drVdA,np.inner(drVdA,vcov))
1890    Vol = 1/np.sqrt(rVsq)
1891    sigVol = Vol**3*np.sqrt(srcvlsq)/2.         #ok - checks with GSAS
1892   
1893    dcdA = np.zeros((6,6))
1894    for i in range(6):
1895        pdcdA =np.zeros(6)
1896        A[i] += delt
1897        pdcdA += G2lat.A2cell(A)
1898        A[i] -= 2*delt
1899        pdcdA -= G2lat.A2cell(A)
1900        A[i] += delt
1901        dcdA[i] = pdcdA/(2.*delt)
1902   
1903    sigMat = np.inner(dcdA,np.inner(dcdA,vcov))
1904    var = np.diag(sigMat)
1905    CS = np.where(var>0.,np.sqrt(var),0.)
1906    if SGData['SGLaue'] in ['3', '3m1', '31m', '6/m', '6/mmm','m3','m3m','4/m','4/mmm']:
1907        CS[3:6] = 0.0
1908    return [CS[0],CS[1],CS[2],CS[5],CS[4],CS[3],sigVol]
1909   
1910def SetPhaseData(parmDict,sigDict,Phases,RBIds,covData,RestraintDict=None,pFile=None):
1911    '''Called after a refinement to transfer parameters from the parameter dict to
1912    the phase(s) information read from a GPX file. Also prints values to the .lst file
1913    '''
1914   
1915    def PrintAtomsAndSig(General,Atoms,atomsSig):
1916        pFile.write('\n Atoms:\n')
1917        line = '   name      x         y         z      frac   Uiso     U11     U22     U33     U12     U13     U23'
1918        if General['Type'] == 'macromolecular':
1919            line = ' res no residue chain '+line
1920        cx,ct,cs,cia = General['AtomPtrs']
1921        pFile.write(line+'\n')
1922        pFile.write(135*'-'+'\n')
1923        fmt = {0:'%7s',ct:'%7s',cx:'%10.5f',cx+1:'%10.5f',cx+2:'%10.5f',cx+3:'%8.3f',cia+1:'%8.5f',
1924            cia+2:'%8.5f',cia+3:'%8.5f',cia+4:'%8.5f',cia+5:'%8.5f',cia+6:'%8.5f',cia+7:'%8.5f'}
1925        noFXsig = {cx:[10*' ','%10s'],cx+1:[10*' ','%10s'],cx+2:[10*' ','%10s'],cx+3:[8*' ','%8s']}
1926        for atyp in General['AtomTypes']:       #zero composition
1927            General['NoAtoms'][atyp] = 0.
1928        for i,at in enumerate(Atoms):
1929            General['NoAtoms'][at[ct]] += at[cx+3]*float(at[cx+5])     #new composition
1930            if General['Type'] == 'macromolecular':
1931                name = ' %s %s %s %s:'%(at[0],at[1],at[2],at[3])
1932                valstr = ' values:          '
1933                sigstr = ' sig   :          '
1934            else:
1935                name = fmt[0]%(at[ct-1])+fmt[1]%(at[ct])+':'
1936                valstr = ' values:'
1937                sigstr = ' sig   :'
1938            for ind in range(cx,cx+4):
1939                sigind = str(i)+':'+str(ind)
1940                valstr += fmt[ind]%(at[ind])                   
1941                if sigind in atomsSig:
1942                    sigstr += fmt[ind]%(atomsSig[sigind])
1943                else:
1944                    sigstr += noFXsig[ind][1]%(noFXsig[ind][0])
1945            if at[cia] == 'I':
1946                valstr += fmt[cia+1]%(at[cia+1])
1947                if '%d:%d'%(i,cia+1) in atomsSig:
1948                    sigstr += fmt[cia+1]%(atomsSig['%d:%d'%(i,cia+1)])
1949                else:
1950                    sigstr += 8*' '
1951            else:
1952                valstr += 8*' '
1953                sigstr += 8*' '
1954                for ind in range(cia+2,cia+8):
1955                    sigind = str(i)+':'+str(ind)
1956                    valstr += fmt[ind]%(at[ind])
1957                    if sigind in atomsSig:                       
1958                        sigstr += fmt[ind]%(atomsSig[sigind])
1959                    else:
1960                        sigstr += 8*' '
1961            pFile.write(name+'\n')
1962            pFile.write(valstr+'\n')
1963            pFile.write(sigstr+'\n')
1964           
1965    def PrintMomentsAndSig(General,Atoms,atomsSig):
1966        cell = General['Cell'][1:7]
1967        G = G2lat.fillgmat(cell)
1968        ast = np.sqrt(np.diag(G))
1969        GS = G/np.outer(ast,ast)
1970        pFile.write('\n Magnetic Moments:\n')    #add magnitude & angle, etc.? TBD
1971        line = '   name       Mx        My        Mz       |Mag|'
1972        cx,ct,cs,cia = General['AtomPtrs']
1973        cmx = cx+4
1974        AtInfo = dict(zip(General['AtomTypes'],General['Lande g']))
1975        pFile.write(line+'\n')
1976        pFile.write(135*'-'+'\n')
1977        fmt = {0:'%7s',ct:'%7s',cmx:'%10.3f',cmx+1:'%10.3f',cmx+2:'%10.3f'}
1978        noFXsig = {cmx:[10*' ','%10s'],cmx+1:[10*' ','%10s'],cmx+2:[10*' ','%10s']}
1979        for i,at in enumerate(Atoms):
1980            if AtInfo[at[ct]]:
1981                name = fmt[0]%(at[ct-1])+fmt[1]%(at[ct])+':'
1982                valstr = ' values:'
1983                sigstr = ' sig   :'
1984                for ind in range(cmx,cmx+3):
1985                    sigind = str(i)+':'+str(ind)
1986                    valstr += fmt[ind]%(at[ind])                   
1987                    if sigind in atomsSig:
1988                        sigstr += fmt[ind]%(atomsSig[sigind])
1989                    else:
1990                        sigstr += noFXsig[ind][1]%(noFXsig[ind][0])
1991                mag = np.array(at[cmx:cmx+3])
1992                Mag = np.sqrt(np.inner(mag,np.inner(mag,GS)))
1993                valstr += '%10.3f'%Mag
1994                sigstr += 10*' '
1995                pFile.write(name+'\n')
1996                pFile.write(valstr+'\n')
1997                pFile.write(sigstr+'\n')
1998           
1999    def PrintWavesAndSig(General,Atoms,wavesSig):
2000        cx,ct,cs,cia = General['AtomPtrs']
2001        pFile.write('\n Modulation waves\n')
2002        names = {'Sfrac':['Fsin','Fcos','Fzero','Fwid'],'Spos':['Xsin','Ysin','Zsin','Xcos','Ycos','Zcos','Tmin','Tmax','Xmax','Ymax','Zmax'],
2003            'Sadp':['U11sin','U22sin','U33sin','U12sin','U13sin','U23sin','U11cos','U22cos',
2004            'U33cos','U12cos','U13cos','U23cos'],'Smag':['MXsin','MYsin','MZsin','MXcos','MYcos','MZcos']}
2005        pFile.write(135*'-'+'\n')
2006        for i,at in enumerate(Atoms):
2007            AtomSS = at[-1]['SS1']
2008            for Stype in ['Sfrac','Spos','Sadp','Smag']:
2009                Waves = AtomSS[Stype]
2010                if len(Waves) > 1:
2011                    waveType = Waves[0]
2012                else:
2013                    continue
2014                if len(Waves):
2015                    pFile.write(' atom: %s, site sym: %s, type: %s wave type: %s:\n'%
2016                        (at[ct-1],at[cs],Stype,waveType))
2017                    for iw,wave in enumerate(Waves[1:]):
2018                        stiw = ':'+str(i)+':'+str(iw)
2019                        namstr = '  names :'
2020                        valstr = '  values:'
2021                        sigstr = '  esds  :'
2022                        if Stype == 'Spos':
2023                            nt = 6
2024                            ot = 0
2025                            if waveType in ['ZigZag','Block',] and not iw:
2026                                nt = 5
2027                                ot = 6
2028                            for j in range(nt):
2029                                name = names['Spos'][j+ot]
2030                                namstr += '%12s'%(name)
2031                                valstr += '%12.4f'%(wave[0][j])
2032                                if name+stiw in wavesSig:
2033                                    sigstr += '%12.4f'%(wavesSig[name+stiw])
2034                                else:
2035                                    sigstr += 12*' '
2036                        elif Stype == 'Sfrac':
2037                            ot = 0
2038                            if 'Crenel' in waveType and not iw:
2039                                ot = 2
2040                            for j in range(2):
2041                                name = names['Sfrac'][j+ot]
2042                                namstr += '%12s'%(names['Sfrac'][j+ot])
2043                                valstr += '%12.4f'%(wave[0][j])
2044                                if name+stiw in wavesSig:
2045                                    sigstr += '%12.4f'%(wavesSig[name+stiw])
2046                                else:
2047                                    sigstr += 12*' '
2048                        elif Stype == 'Sadp':
2049                            for j in range(12):
2050                                name = names['Sadp'][j]
2051                                namstr += '%10s'%(names['Sadp'][j])
2052                                valstr += '%10.6f'%(wave[0][j])
2053                                if name+stiw in wavesSig:
2054                                    sigstr += '%10.6f'%(wavesSig[name+stiw])
2055                                else:
2056                                    sigstr += 10*' '
2057                        elif Stype == 'Smag':
2058                            for j in range(6):
2059                                name = names['Smag'][j]
2060                                namstr += '%12s'%(names['Smag'][j])
2061                                valstr += '%12.4f'%(wave[0][j])
2062                                if name+stiw in wavesSig:
2063                                    sigstr += '%12.4f'%(wavesSig[name+stiw])
2064                                else:
2065                                    sigstr += 12*' '
2066                               
2067                    pFile.write(namstr+'\n')
2068                    pFile.write(valstr+'\n')
2069                    pFile.write(sigstr+'\n')
2070       
2071               
2072    def PrintRBObjPOAndSig(rbfx,rbsx):
2073        for i in WriteRBObjPOAndSig(pfx,rbfx,rbsx,parmDict,sigDict):
2074            pFile.write(i+'\n')
2075       
2076    def PrintRBObjTLSAndSig(rbfx,rbsx,TLS):
2077        for i in WriteRBObjTLSAndSig(pfx,rbfx,rbsx,TLS,parmDict,sigDict):
2078            pFile.write(i)
2079       
2080    def PrintRBObjTorAndSig(rbsx):
2081        nTors = len(RBObj['Torsions'])
2082        if nTors:
2083            for i in WriteRBObjTorAndSig(pfx,rbsx,parmDict,sigDict,nTors):
2084                pFile.write(i)
2085               
2086    def PrintSHtextureAndSig(textureData,SHtextureSig):
2087        Tindx = 1.0
2088        Tvar = 0.0
2089        pFile.write('\n Spherical harmonics texture: Order: %d\n'%textureData['Order'])
2090        names = ['omega','chi','phi']
2091        namstr = '  names :'
2092        ptstr =  '  values:'
2093        sigstr = '  esds  :'
2094        for name in names:
2095            namstr += '%12s'%(name)
2096            ptstr += '%12.3f'%(textureData['Sample '+name][1])
2097            if 'Sample '+name in SHtextureSig:
2098                sigstr += '%12.3f'%(SHtextureSig['Sample '+name])
2099            else:
2100                sigstr += 12*' '
2101        pFile.write(namstr+'\n')
2102        pFile.write(ptstr+'\n')
2103        pFile.write(sigstr+'\n')
2104        pFile.write('\n Texture coefficients:\n')
2105        SHcoeff = textureData['SH Coeff'][1]
2106        SHkeys = list(SHcoeff.keys())
2107        nCoeff = len(SHcoeff)
2108        nBlock = nCoeff//10+1
2109        iBeg = 0
2110        iFin = min(iBeg+10,nCoeff)
2111        for block in range(nBlock):
2112            namstr = '  names :'
2113            ptstr =  '  values:'
2114            sigstr = '  esds  :'
2115            for name in SHkeys[iBeg:iFin]:
2116                namstr += '%12s'%(name)
2117                ptstr += '%12.3f'%(SHcoeff[name])
2118                l = 2.0*eval(name.strip('C'))[0]+1
2119                Tindx += SHcoeff[name]**2/l
2120                if name in SHtextureSig:
2121                    Tvar += (2.*SHcoeff[name]*SHtextureSig[name]/l)**2
2122                    sigstr += '%12.3f'%(SHtextureSig[name])
2123                else:
2124                    sigstr += 12*' '
2125            pFile.write(namstr+'\n')
2126            pFile.write(ptstr+'\n')
2127            pFile.write(sigstr+'\n')
2128            iBeg += 10
2129            iFin = min(iBeg+10,nCoeff)
2130        pFile.write(' Texture index J = %.3f(%d)'%(Tindx,int(1000*np.sqrt(Tvar))))
2131           
2132    ##########################################################################
2133    # SetPhaseData starts here
2134    pFile.write('\n Phases:\n')
2135    for phase in Phases:
2136        pFile.write(' Result for phase: %s\n'%phase)
2137        pFile.write(135*'='+'\n')
2138        Phase = Phases[phase]
2139        General = Phase['General']
2140        SGData = General['SGData']
2141        Atoms = Phase['Atoms']
2142        AtLookup = []
2143        if Atoms and not General.get('doPawley'):
2144            cx,ct,cs,cia = General['AtomPtrs']
2145            AtLookup = G2mth.FillAtomLookUp(Atoms,cia+8)
2146        cell = General['Cell']
2147        pId = Phase['pId']
2148        pfx = str(pId)+'::'
2149        if cell[0]:
2150            A,sigA = cellFill(pfx,SGData,parmDict,sigDict)
2151            cellSig = getCellEsd(pfx,SGData,A,covData)  #includes sigVol
2152            pFile.write(' Reciprocal metric tensor: \n')
2153            ptfmt = "%15.9f"
2154            names = ['A11','A22','A33','A12','A13','A23']
2155            namstr = '  names :'
2156            ptstr =  '  values:'
2157            sigstr = '  esds  :'
2158            for name,a,siga in zip(names,A,sigA):
2159                namstr += '%15s'%(name)
2160                ptstr += ptfmt%(a)
2161                if siga:
2162                    sigstr += ptfmt%(siga)
2163                else:
2164                    sigstr += 15*' '
2165            pFile.write(namstr+'\n')
2166            pFile.write(ptstr+'\n')
2167            pFile.write(sigstr+'\n')
2168            cell[1:7] = G2lat.A2cell(A)
2169            cell[7] = G2lat.calc_V(A)
2170            pFile.write(' New unit cell:\n')
2171            ptfmt = ["%12.6f","%12.6f","%12.6f","%12.4f","%12.4f","%12.4f","%12.3f"]
2172            names = ['a','b','c','alpha','beta','gamma','Volume']
2173            namstr = '  names :'
2174            ptstr =  '  values:'
2175            sigstr = '  esds  :'
2176            for name,fmt,a,siga in zip(names,ptfmt,cell[1:8],cellSig):
2177                namstr += '%12s'%(name)
2178                ptstr += fmt%(a)
2179                if siga:
2180                    sigstr += fmt%(siga)
2181                else:
2182                    sigstr += 12*' '
2183            pFile.write(namstr+'\n')
2184            pFile.write(ptstr+'\n')
2185            pFile.write(sigstr+'\n')
2186        ik = 6  #for Pawley stuff below
2187        if General.get('Modulated',False):
2188            ik = 7
2189            Vec,vRef,maxH = General['SuperVec']
2190            if vRef:
2191                pFile.write(' New modulation vector:\n')
2192                namstr = '  names :'
2193                ptstr =  '  values:'
2194                sigstr = '  esds  :'
2195                for iv,var in enumerate(['mV0','mV1','mV2']):
2196                    namstr += '%12s'%(pfx+var)
2197                    ptstr += '%12.6f'%(parmDict[pfx+var])
2198                    if pfx+var in sigDict:
2199                        Vec[iv] = parmDict[pfx+var]
2200                        sigstr += '%12.6f'%(sigDict[pfx+var])
2201                    else:
2202                        sigstr += 12*' '
2203                pFile.write(namstr+'\n')
2204                pFile.write(ptstr+'\n')
2205                pFile.write(sigstr+'\n')
2206           
2207        General['Mass'] = 0.
2208        if Phase['General'].get('doPawley'):
2209            pawleyRef = Phase['Pawley ref']
2210            for i,refl in enumerate(pawleyRef):
2211                key = pfx+'PWLref:'+str(i)
2212                refl[ik] = parmDict[key]
2213                if key in sigDict:
2214                    refl[ik+1] = sigDict[key]
2215                else:
2216                    refl[ik+1] = 0
2217        else:
2218            VRBIds = RBIds['Vector']
2219            RRBIds = RBIds['Residue']
2220            RBModels = Phase['RBModels']
2221            for irb,RBObj in enumerate(RBModels.get('Vector',[])):
2222                jrb = VRBIds.index(RBObj['RBId'])
2223                rbsx = str(irb)+':'+str(jrb)
2224                pFile.write(' Vector rigid body parameters:\n')
2225                PrintRBObjPOAndSig('RBV',rbsx)
2226                PrintRBObjTLSAndSig('RBV',rbsx,RBObj['ThermalMotion'][0])
2227            for irb,RBObj in enumerate(RBModels.get('Residue',[])):
2228                jrb = RRBIds.index(RBObj['RBId'])
2229                rbsx = str(irb)+':'+str(jrb)
2230                pFile.write(' Residue rigid body parameters:\n')
2231                PrintRBObjPOAndSig('RBR',rbsx)
2232                PrintRBObjTLSAndSig('RBR',rbsx,RBObj['ThermalMotion'][0])
2233                PrintRBObjTorAndSig(rbsx)
2234            atomsSig = {}
2235            wavesSig = {}
2236            cx,ct,cs,cia = General['AtomPtrs']
2237            for i,at in enumerate(Atoms):
2238                names = {cx:pfx+'Ax:'+str(i),cx+1:pfx+'Ay:'+str(i),cx+2:pfx+'Az:'+str(i),cx+3:pfx+'Afrac:'+str(i),
2239                    cia+1:pfx+'AUiso:'+str(i),cia+2:pfx+'AU11:'+str(i),cia+3:pfx+'AU22:'+str(i),cia+4:pfx+'AU33:'+str(i),
2240                    cia+5:pfx+'AU12:'+str(i),cia+6:pfx+'AU13:'+str(i),cia+7:pfx+'AU23:'+str(i),
2241                    cx+4:pfx+'AMx:'+str(i),cx+5:pfx+'AMy:'+str(i),cx+6:pfx+'AMz:'+str(i)}
2242                for ind in range(cx,cx+4):
2243                    at[ind] = parmDict[names[ind]]
2244                    if ind in range(cx,cx+3):
2245                        name = names[ind].replace('A','dA')
2246                    else:
2247                        name = names[ind]
2248                    if name in sigDict:
2249                        atomsSig[str(i)+':'+str(ind)] = sigDict[name]
2250                if at[cia] == 'I':
2251                    at[cia+1] = parmDict[names[cia+1]]
2252                    if names[cia+1] in sigDict:
2253                        atomsSig['%d:%d'%(i,cia+1)] = sigDict[names[cia+1]]
2254                else:
2255                    for ind in range(cia+2,cia+8):
2256                        at[ind] = parmDict[names[ind]]
2257                        if names[ind] in sigDict:
2258                            atomsSig[str(i)+':'+str(ind)] = sigDict[names[ind]]
2259                if General['Type'] == 'magnetic':
2260                    for ind in range(cx+4,cx+7):
2261                        at[ind] = parmDict[names[ind]]
2262                        if names[ind] in sigDict:
2263                            atomsSig[str(i)+':'+str(ind)] = sigDict[names[ind]]
2264                ind = General['AtomTypes'].index(at[ct])
2265                General['Mass'] += General['AtomMass'][ind]*at[cx+3]*at[cx+5]
2266                if General.get('Modulated',False):
2267                    AtomSS = at[-1]['SS1']
2268                    for Stype in ['Sfrac','Spos','Sadp','Smag']:
2269                        Waves = AtomSS[Stype]
2270                        if len(Waves):
2271                            waveType = Waves[0]
2272                        else:
2273                            continue
2274                        for iw,wave in enumerate(Waves[1:]):
2275                            stiw = str(i)+':'+str(iw)
2276                            if Stype == 'Spos':
2277                                if waveType in ['ZigZag','Block',] and not iw:
2278                                    names = ['Tmin:'+stiw,'Tmax:'+stiw,'Xmax:'+stiw,'Ymax:'+stiw,'Zmax:'+stiw]
2279                                else:
2280                                    names = ['Xsin:'+stiw,'Ysin:'+stiw,'Zsin:'+stiw,
2281                                        'Xcos:'+stiw,'Ycos:'+stiw,'Zcos:'+stiw]
2282                            elif Stype == 'Sadp':
2283                                names = ['U11sin:'+stiw,'U22sin:'+stiw,'U33sin:'+stiw,
2284                                    'U12sin:'+stiw,'U13sin:'+stiw,'U23sin:'+stiw,
2285                                    'U11cos:'+stiw,'U22cos:'+stiw,'U33cos:'+stiw,
2286                                    'U12cos:'+stiw,'U13cos:'+stiw,'U23cos:'+stiw]
2287                            elif Stype == 'Sfrac':
2288                                if 'Crenel' in waveType and not iw:
2289                                    names = ['Fzero:'+stiw,'Fwid:'+stiw]
2290                                else:
2291                                    names = ['Fsin:'+stiw,'Fcos:'+stiw]
2292                            elif Stype == 'Smag':
2293                                names = ['MXsin:'+stiw,'MYsin:'+stiw,'MZsin:'+stiw,
2294                                    'MXcos:'+stiw,'MYcos:'+stiw,'MZcos:'+stiw]
2295                            for iname,name in enumerate(names):
2296                                AtomSS[Stype][iw+1][0][iname] = parmDict[pfx+name]
2297                                if pfx+name in sigDict:
2298                                    wavesSig[name] = sigDict[pfx+name]
2299                   
2300            PrintAtomsAndSig(General,Atoms,atomsSig)
2301            if General['Type'] == 'magnetic':
2302                PrintMomentsAndSig(General,Atoms,atomsSig)
2303            if General.get('Modulated',False):
2304                PrintWavesAndSig(General,Atoms,wavesSig)
2305               
2306            density = G2mth.getDensity(General)[0]
2307            pFile.write('\n Density: %f.4 g/cm**3\n'%density)
2308           
2309       
2310        textureData = General['SH Texture']   
2311        if textureData['Order']:
2312            SHtextureSig = {}
2313            for name in ['omega','chi','phi']:
2314                aname = pfx+'SH '+name
2315                textureData['Sample '+name][1] = parmDict[aname]
2316                if aname in sigDict:
2317                    SHtextureSig['Sample '+name] = sigDict[aname]
2318            for name in textureData['SH Coeff'][1]:
2319                aname = pfx+name
2320                textureData['SH Coeff'][1][name] = parmDict[aname]
2321                if aname in sigDict:
2322                    SHtextureSig[name] = sigDict[aname]
2323            PrintSHtextureAndSig(textureData,SHtextureSig)
2324        if phase in RestraintDict and not Phase['General'].get('doPawley'):
2325            PrintRestraints(cell[1:7],SGData,General['AtomPtrs'],Atoms,AtLookup,
2326                textureData,RestraintDict[phase],pFile)
2327                   
2328################################################################################
2329##### Histogram & Phase data
2330################################################################################       
2331                   
2332def GetHistogramPhaseData(Phases,Histograms,Print=True,pFile=None,resetRefList=True):
2333    '''Loads the HAP histogram/phase information into dicts
2334
2335    :param dict Phases: phase information
2336    :param dict Histograms: Histogram information
2337    :param bool Print: prints information as it is read
2338    :param file pFile: file object to print to (the default, None causes printing to the console)
2339    :param bool resetRefList: Should the contents of the Reflection List be initialized
2340      on loading. The default, True, initializes the Reflection List as it is loaded.
2341
2342    :returns: (hapVary,hapDict,controlDict)
2343      * hapVary: list of refined variables
2344      * hapDict: dict with refined variables and their values
2345      * controlDict: dict with fixed parameters
2346    '''
2347   
2348    def PrintSize(hapData):
2349        if hapData[0] in ['isotropic','uniaxial']:
2350            line = '\n Size model    : %9s'%(hapData[0])
2351            line += ' equatorial:'+'%12.3f'%(hapData[1][0])+' Refine? '+str(hapData[2][0])
2352            if hapData[0] == 'uniaxial':
2353                line += ' axial:'+'%12.3f'%(hapData[1][1])+' Refine? '+str(hapData[2][1])
2354            line += '\n\t LG mixing coeff.: %12.4f'%(hapData[1][2])+' Refine? '+str(hapData[2][2])
2355            pFile.write(line+'\n')
2356        else:
2357            pFile.write('\n Size model    : %s\n\t LG mixing coeff.:%12.4f Refine? %s\n'%
2358                (hapData[0],hapData[1][2],hapData[2][2]))
2359            Snames = ['S11','S22','S33','S12','S13','S23']
2360            ptlbls = ' names :'
2361            ptstr =  ' values:'
2362            varstr = ' refine:'
2363            for i,name in enumerate(Snames):
2364                ptlbls += '%12s' % (name)
2365                ptstr += '%12.3f' % (hapData[4][i])
2366                varstr += '%12s' % (str(hapData[5][i]))
2367            pFile.write(ptlbls+'\n')
2368            pFile.write(ptstr+'\n')
2369            pFile.write(varstr+'\n')
2370       
2371    def PrintMuStrain(hapData,SGData):
2372        if hapData[0] in ['isotropic','uniaxial']:
2373            line = '\n Mustrain model: %9s'%(hapData[0])
2374            line += ' equatorial:'+'%12.1f'%(hapData[1][0])+' Refine? '+str(hapData[2][0])
2375            if hapData[0] == 'uniaxial':
2376                line += ' axial:'+'%12.1f'%(hapData[1][1])+' Refine? '+str(hapData[2][1])
2377            line +='\n\t LG mixing coeff.:%12.4f'%(hapData[1][2])+' Refine? '+str(hapData[2][2])
2378            pFile.write(line+'\n')
2379        else:
2380            pFile.write('\n Mustrain model: %s\n\t LG mixing coeff.:%12.4f Refine? %s\n'%
2381                (hapData[0],hapData[1][2],hapData[2][2]))
2382            Snames = G2spc.MustrainNames(SGData)
2383            ptlbls = ' names :'
2384            ptstr =  ' values:'
2385            varstr = ' refine:'
2386            for i,name in enumerate(Snames):
2387                ptlbls += '%12s' % (name)
2388                ptstr += '%12.1f' % (hapData[4][i])
2389                varstr += '%12s' % (str(hapData[5][i]))
2390            pFile.write(ptlbls+'\n')
2391            pFile.write(ptstr+'\n')
2392            pFile.write(varstr+'\n')
2393
2394    def PrintHStrain(hapData,SGData):
2395        pFile.write('\n Hydrostatic/elastic strain:\n')
2396        Hsnames = G2spc.HStrainNames(SGData)
2397        ptlbls = ' names :'
2398        ptstr =  ' values:'
2399        varstr = ' refine:'
2400        for i,name in enumerate(Hsnames):
2401            ptlbls += '%12s' % (name)
2402            ptstr += '%12.4g' % (hapData[0][i])
2403            varstr += '%12s' % (str(hapData[1][i]))
2404        pFile.write(ptlbls+'\n')
2405        pFile.write(ptstr+'\n')
2406        pFile.write(varstr+'\n')
2407
2408    def PrintSHPO(hapData):
2409        pFile.write('\n Spherical harmonics preferred orientation: Order: %d Refine? %s\n'%(hapData[4],hapData[2]))
2410        ptlbls = ' names :'
2411        ptstr =  ' values:'
2412        for item in hapData[5]:
2413            ptlbls += '%12s'%(item)
2414            ptstr += '%12.3f'%(hapData[5][item]) 
2415        pFile.write(ptlbls+'\n')
2416        pFile.write(ptstr+'\n')
2417   
2418    def PrintBabinet(hapData):
2419        pFile.write('\n Babinet form factor modification:\n')
2420        ptlbls = ' names :'
2421        ptstr =  ' values:'
2422        varstr = ' refine:'
2423        for name in ['BabA','BabU']:
2424            ptlbls += '%12s' % (name)
2425            ptstr += '%12.6f' % (hapData[name][0])
2426            varstr += '%12s' % (str(hapData[name][1]))
2427        pFile.write(ptlbls+'\n')
2428        pFile.write(ptstr+'\n')
2429        pFile.write(varstr+'\n')
2430       
2431    hapDict = {}
2432    hapVary = []
2433    controlDict = {}
2434   
2435    for phase in Phases:
2436        HistoPhase = Phases[phase]['Histograms']
2437        SGData = Phases[phase]['General']['SGData']
2438        cell = Phases[phase]['General']['Cell'][1:7]
2439        A = G2lat.cell2A(cell)
2440        if Phases[phase]['General'].get('Modulated',False):
2441            SSGData = Phases[phase]['General']['SSGData']
2442            Vec,x,maxH = Phases[phase]['General']['SuperVec']
2443        pId = Phases[phase]['pId']
2444        for histogram in Histograms:
2445            if histogram not in HistoPhase and phase in Histograms[histogram]['Reflection Lists']:
2446                #remove previously created reflection list if histogram is removed from phase
2447                #print("removing ",phase,"from",histogram)
2448                del Histograms[histogram]['Reflection Lists'][phase]
2449        histoList = list(HistoPhase.keys())
2450        histoList.sort()
2451        for histogram in histoList:
2452            try:
2453                Histogram = Histograms[histogram]
2454            except KeyError:                       
2455                #skip if histogram not included e.g. in a sequential refinement
2456                continue
2457            if not HistoPhase[histogram]['Use']:        #remove previously created  & now unused phase reflection list
2458                if phase in Histograms[histogram]['Reflection Lists']:
2459                    del Histograms[histogram]['Reflection Lists'][phase]
2460                continue
2461            hapData = HistoPhase[histogram]
2462            hId = Histogram['hId']
2463            if 'PWDR' in histogram:
2464                limits = Histogram['Limits'][1]
2465                inst = Histogram['Instrument Parameters'][0]    #TODO - grab table here if present
2466                if 'C' in inst['Type'][1]:
2467                    try:
2468                        wave = inst['Lam'][1]
2469                    except KeyError:
2470                        wave = inst['Lam1'][1]
2471                    dmin = wave/(2.0*sind(limits[1]/2.0))
2472                elif 'T' in inst['Type'][0]:
2473                    dmin = limits[0]/inst['difC'][1]
2474                else:
2475                    wave = inst['Lam'][1]
2476                    dmin = wave/(2.0*sind(limits[1]/2.0))
2477                pfx = str(pId)+':'+str(hId)+':'
2478                if Phases[phase]['General']['doPawley']:
2479                    hapDict[pfx+'LeBail'] = False           #Pawley supercedes LeBail
2480                    hapDict[pfx+'newLeBail'] = True
2481                    Tmin = G2lat.Dsp2pos(inst,dmin)
2482                    if 'T' in inst['Type'][1]:
2483                        limits[0] = max(limits[0],Tmin)
2484                    else:
2485                        limits[1] = min(limits[1],Tmin)
2486                else:
2487                    hapDict[pfx+'LeBail'] = hapData.get('LeBail',False)
2488                    hapDict[pfx+'newLeBail'] = hapData.get('newLeBail',True)
2489                if Phases[phase]['General']['Type'] == 'magnetic':
2490                    dmin = max(dmin,Phases[phase]['General'].get('MagDmin',0.))
2491                for item in ['Scale','Extinction']:
2492                    hapDict[pfx+item] = hapData[item][0]
2493                    if hapData[item][1] and not hapDict[pfx+'LeBail']:
2494                        hapVary.append(pfx+item)
2495                names = G2spc.HStrainNames(SGData)
2496                HSvals = []
2497                for i,name in enumerate(names):
2498                    hapDict[pfx+name] = hapData['HStrain'][0][i]
2499                    HSvals.append(hapDict[pfx+name])
2500                    if hapData['HStrain'][1][i]:
2501                        hapVary.append(pfx+name)
2502                if 'Layer Disp' in hapData:
2503                    hapDict[pfx+'LayerDisp'] = hapData['Layer Disp'][0]
2504                    if hapData['Layer Disp'][1]:
2505                        hapVary.append(pfx+'LayerDisp')
2506                else:
2507                    hapDict[pfx+'LayerDisp'] = 0.0
2508                controlDict[pfx+'poType'] = hapData['Pref.Ori.'][0]
2509                if hapData['Pref.Ori.'][0] == 'MD':
2510                    hapDict[pfx+'MD'] = hapData['Pref.Ori.'][1]
2511                    controlDict[pfx+'MDAxis'] = hapData['Pref.Ori.'][3]
2512                    if hapData['Pref.Ori.'][2] and not hapDict[pfx+'LeBail']:
2513                        hapVary.append(pfx+'MD')
2514                else:                           #'SH' spherical harmonics
2515                    controlDict[pfx+'SHord'] = hapData['Pref.Ori.'][4]
2516                    controlDict[pfx+'SHncof'] = len(hapData['Pref.Ori.'][5])
2517                    controlDict[pfx+'SHnames'] = G2lat.GenSHCoeff(SGData['SGLaue'],'0',controlDict[pfx+'SHord'],False)
2518                    controlDict[pfx+'SHhkl'] = []
2519                    try: #patch for old Pref.Ori. items
2520                        controlDict[pfx+'SHtoler'] = 0.1
2521                        if hapData['Pref.Ori.'][6][0] != '':
2522                            controlDict[pfx+'SHhkl'] = [eval(a.replace(' ',',')) for a in hapData['Pref.Ori.'][6]]
2523                        controlDict[pfx+'SHtoler'] = hapData['Pref.Ori.'][7]
2524                    except IndexError:
2525                        pass
2526                    for item in hapData['Pref.Ori.'][5]:
2527                        hapDict[pfx+item] = hapData['Pref.Ori.'][5][item]
2528                        if hapData['Pref.Ori.'][2] and not hapDict[pfx+'LeBail']:
2529                            hapVary.append(pfx+item)
2530                for item in ['Mustrain','Size']:
2531                    controlDict[pfx+item+'Type'] = hapData[item][0]
2532                    hapDict[pfx+item+';mx'] = hapData[item][1][2]
2533                    if hapData[item][2][2]:
2534                        hapVary.append(pfx+item+';mx')
2535                    if hapData[item][0] in ['isotropic','uniaxial']:
2536                        hapDict[pfx+item+';i'] = hapData[item][1][0]
2537                        if hapData[item][2][0]:
2538                            hapVary.append(pfx+item+';i')
2539                        if hapData[item][0] == 'uniaxial':
2540                            controlDict[pfx+item+'Axis'] = hapData[item][3]
2541                            hapDict[pfx+item+';a'] = hapData[item][1][1]
2542                            if hapData[item][2][1]:
2543                                hapVary.append(pfx+item+';a')
2544                    else:       #generalized for mustrain or ellipsoidal for size
2545                        Nterms = len(hapData[item][4])
2546                        if item == 'Mustrain':
2547                            names = G2spc.MustrainNames(SGData)
2548                            pwrs = []
2549                            for name in names:
2550                                h,k,l = name[1:]
2551                                pwrs.append([int(h),int(k),int(l)])
2552                            controlDict[pfx+'MuPwrs'] = pwrs
2553                        for i in range(Nterms):
2554                            sfx = ';'+str(i)
2555                            hapDict[pfx+item+sfx] = hapData[item][4][i]
2556                            if hapData[item][5][i]:
2557                                hapVary.append(pfx+item+sfx)
2558                if Phases[phase]['General']['Type'] != 'magnetic':
2559                    for bab in ['BabA','BabU']:
2560                        hapDict[pfx+bab] = hapData['Babinet'][bab][0]
2561                        if hapData['Babinet'][bab][1] and not hapDict[pfx+'LeBail']:
2562                            hapVary.append(pfx+bab)
2563                               
2564                if Print: 
2565                    pFile.write('\n Phase: %s in histogram: %s\n'%(phase,histogram))
2566                    pFile.write(135*'='+'\n')
2567                    if hapDict[pfx+'LeBail']:
2568                        pFile.write(' Perform LeBail extraction\n')                     
2569                    else:
2570                        pFile.write(' Phase fraction  : %10.4f Refine? %s\n'%(hapData['Scale'][0],hapData['Scale'][1]))
2571                        pFile.write(' Extinction coeff: %10.4f Refine? %s\n'%(hapData['Extinction'][0],hapData['Extinction'][1]))
2572                        if hapData['Pref.Ori.'][0] == 'MD':
2573                            Ax = hapData['Pref.Ori.'][3]
2574                            pFile.write(' March-Dollase PO: %10.4f Refine? %s Axis: %d %d %d\n'%
2575                                (hapData['Pref.Ori.'][1],hapData['Pref.Ori.'][2],Ax[0],Ax[1],Ax[2]))
2576                        else: #'SH' for spherical harmonics
2577                            PrintSHPO(hapData['Pref.Ori.'])
2578                            pFile.write(' Penalty hkl list: %s tolerance: %.2f\n'%(controlDict[pfx+'SHhkl'],controlDict[pfx+'SHtoler']))
2579                    PrintSize(hapData['Size'])
2580                    PrintMuStrain(hapData['Mustrain'],SGData)
2581                    PrintHStrain(hapData['HStrain'],SGData)
2582                    if 'Layer Disp' in hapData:
2583                        pFile.write(' Layer Displacement: %10.3f Refine? %s\n'%(hapData['Layer Disp'][0],hapData['Layer Disp'][1]))
2584                    if Phases[phase]['General']['Type'] != 'magnetic':
2585                        if hapData['Babinet']['BabA'][0]:
2586                            PrintBabinet(hapData['Babinet'])
2587                if phase in Histogram['Reflection Lists'] and 'RefList' not in Histogram['Reflection Lists'][phase] and hapData.get('LeBail',False):
2588                    hapData['newLeBail'] = True
2589                if resetRefList and (not hapDict[pfx+'LeBail'] or (hapData.get('LeBail',False) and hapData['newLeBail'])):
2590                    if hapData.get('LeBail',True):         #stop regeneating reflections for LeBail
2591                        hapData['newLeBail'] = False
2592                    refList = []
2593#                    Uniq = []
2594#                    Phi = []
2595                    useExt = 'magnetic' in Phases[phase]['General']['Type'] and 'N' in inst['Type'][0]
2596                    if Phases[phase]['General'].get('Modulated',False):
2597                        ifSuper = True
2598                        HKLd = np.array(G2lat.GenSSHLaue(dmin,SGData,SSGData,Vec,maxH,A))
2599                        HKLd = G2mth.sortArray(HKLd,4,reverse=True)
2600                        for h,k,l,m,d in HKLd:
2601                            ext,mul,uniq,phi = G2spc.GenHKLf([h,k,l],SGData)
2602                            mul *= 2      # for powder overlap of Friedel pairs
2603                            if m or not ext or useExt:
2604                                if 'C' in inst['Type'][0]:
2605                                    pos = G2lat.Dsp2pos(inst,d)
2606                                    if limits[0] < pos < limits[1]:
2607                                        refList.append([h,k,l,m,mul,d, pos,0.0,0.0,0.0,1., 0.0,0.0,1.0,1.0,1.0])
2608                                        #... sig,gam,fotsq,fctsq, phase,icorr,prfo,abs,ext
2609#                                        Uniq.append(uniq)
2610#                                        Phi.append(phi)
2611                                elif 'T' in inst['Type'][0]:
2612                                    pos = G2lat.Dsp2pos(inst,d)
2613                                    if limits[0] < pos < limits[1]:
2614                                        wave = inst['difC'][1]*d/(252.816*inst['fltPath'][0])
2615                                        refList.append([h,k,l,m,mul,d, pos,0.0,0.0,0.0,1., 0.0,0.0,0.0,0.0,wave, 1.0,1.0,1.0])
2616                                        # ... sig,gam,fotsq,fctsq, phase,icorr,alp,bet,wave, prfo,abs,ext
2617                                        #TODO - if tabulated put alp & bet in here
2618#                                        Uniq.append(uniq)
2619#                                        Phi.append(phi)
2620                                elif 'B' in inst['Type'][0]:
2621                                    pos = G2lat.Dsp2pos(inst,d)
2622                                    if limits[0] < pos < limits[1]:
2623                                        refList.append([h,k,l,m,mul,d, pos,0.0,0.0,0.0,1., 0.0,0.0,0.0,0.0, 1.0,1.0,1.0])
2624                                        # ... sig,gam,fotsq,fctsq, phase,icorr,alp,bet, prfo,abs,ext
2625                    else:
2626                        ifSuper = False
2627                        HKLd = np.array(G2lat.GenHLaue(dmin,SGData,A))
2628                        HKLd = G2mth.sortArray(HKLd,3,reverse=True)
2629                        for h,k,l,d in HKLd:
2630                            ext,mul,uniq,phi = G2spc.GenHKLf([h,k,l],SGData)
2631                            if ext and 'N' in inst['Type'][0] and  'MagSpGrp' in SGData:
2632                                ext = G2spc.checkMagextc([h,k,l],SGData)
2633                            mul *= 2      # for powder overlap of Friedel pairs
2634                            if ext and not useExt:
2635                                continue
2636                            if 'C' in inst['Type'][0]:
2637                                pos = G2lat.Dsp2pos(inst,d)
2638                                if limits[0] < pos < limits[1]:
2639                                    refList.append([h,k,l,mul,d, pos,0.0,0.0,0.0,1., 0.0,0.0,1.0,1.0,1.0])
2640                                    #... sig,gam,fotsq,fctsq, phase,icorr,prfo,abs,ext
2641#                                    Uniq.append(uniq)
2642#                                    Phi.append(phi)
2643                            elif 'T' in inst['Type'][0]:
2644                                pos = G2lat.Dsp2pos(inst,d)
2645                                if limits[0] < pos < limits[1]:
2646                                    wave = inst['difC'][1]*d/(252.816*inst['fltPath'][0])
2647                                    refList.append([h,k,l,mul,d, pos,0.0,0.0,0.0,1., 0.0,0.0,0.0,0.0,wave, 1.0,1.0,1.0])
2648                                    # ... sig,gam,fotsq,fctsq, phase,icorr,alp,bet,wave, prfo,abs,ext
2649#                                    Uniq.append(uniq)
2650#                                    Phi.append(phi)
2651                            elif 'B' in inst['Type'][0]:
2652                                pos = G2lat.Dsp2pos(inst,d)
2653                                if limits[0] < pos < limits[1]:
2654                                    refList.append([h,k,l,mul,d, pos,0.0,0.0,0.0,1., 0.0,0.0,0.0,0.0, 1.0,1.0,1.0])
2655                                    # ... sig,gam,fotsq,fctsq, phase,icorr,alp,bet, prfo,abs,ext
2656                    Histogram['Reflection Lists'][phase] = {'RefList':np.array(refList),'FF':{},'Type':inst['Type'][0],'Super':ifSuper}
2657            elif 'HKLF' in histogram:
2658                inst = Histogram['Instrument Parameters'][0]
2659                hId = Histogram['hId']
2660                hfx = ':%d:'%(hId)
2661                for item in inst:
2662                    if type(inst) is not list and item != 'Type': continue # skip over non-refined items (such as InstName)
2663                    hapDict[hfx+item] = inst[item][1]
2664                pfx = str(pId)+':'+str(hId)+':'
2665                hapDict[pfx+'Scale'] = hapData['Scale'][0]
2666                if hapData['Scale'][1]:
2667                    hapVary.append(pfx+'Scale')
2668                               
2669                extApprox,extType,extParms = hapData['Extinction']
2670                controlDict[pfx+'EType'] = extType
2671                controlDict[pfx+'EApprox'] = extApprox
2672                if 'C' in inst['Type'][0]:
2673                    controlDict[pfx+'Tbar'] = extParms['Tbar']
2674                    controlDict[pfx+'Cos2TM'] = extParms['Cos2TM']
2675                if 'Primary' in extType:
2676                    Ekey = ['Ep',]
2677                elif 'I & II' in extType:
2678                    Ekey = ['Eg','Es']
2679                elif 'Secondary Type II' == extType:
2680                    Ekey = ['Es',]
2681                elif 'Secondary Type I' == extType:
2682                    Ekey = ['Eg',]
2683                else:   #'None'
2684                    Ekey = []
2685                for eKey in Ekey:
2686                    hapDict[pfx+eKey] = extParms[eKey][0]
2687                    if extParms[eKey][1]:
2688                        hapVary.append(pfx+eKey)
2689                for bab in ['BabA','BabU']:
2690                    hapDict[pfx+bab] = hapData['Babinet'][bab][0]
2691                    if hapData['Babinet'][bab][1]:
2692                        hapVary.append(pfx+bab)
2693                Twins = hapData.get('Twins',[[np.array([[1,0,0],[0,1,0],[0,0,1]]),[1.0,False,0]],])
2694                if len(Twins) == 1:
2695                    hapDict[pfx+'Flack'] = hapData.get('Flack',[0.,False])[0]
2696                    if hapData.get('Flack',[0,False])[1]:
2697                        hapVary.append(pfx+'Flack')
2698                sumTwFr = 0.
2699                controlDict[pfx+'TwinLaw'] = []
2700                controlDict[pfx+'TwinInv'] = []
2701                NTL = 0           
2702                for it,twin in enumerate(Twins):
2703                    if 'bool' in str(type(twin[0])):
2704                        controlDict[pfx+'TwinInv'].append(twin[0])
2705                        controlDict[pfx+'TwinLaw'].append(np.zeros((3,3)))
2706                    else:
2707                        NTL += 1
2708                        controlDict[pfx+'TwinInv'].append(False)
2709                        controlDict[pfx+'TwinLaw'].append(twin[0])
2710                    if it:
2711                        hapDict[pfx+'TwinFr:'+str(it)] = twin[1]
2712                        sumTwFr += twin[1]
2713                    else:
2714                        hapDict[pfx+'TwinFr:0'] = twin[1][0]
2715                        controlDict[pfx+'TwinNMN'] = twin[1][1]
2716                    if Twins[0][1][1]:
2717                        hapVary.append(pfx+'TwinFr:'+str(it))
2718                controlDict[pfx+'NTL'] = NTL
2719                #need to make constraint on TwinFr
2720                controlDict[pfx+'TwinLaw'] = np.array(controlDict[pfx+'TwinLaw'])
2721                if len(Twins) > 1:    #force sum to unity
2722                    hapDict[pfx+'TwinFr:0'] = 1.-sumTwFr
2723                if Print: 
2724                    pFile.write('\n Phase: %s in histogram: %s\n'%(phase,histogram))
2725                    pFile.write(135*'='+'\n')
2726                    pFile.write(' Scale factor     : %10.4f Refine? %s\n'%(hapData['Scale'][0],hapData['Scale'][1]))
2727                    if extType != 'None':
2728                        pFile.write(' Extinction  Type: %15s approx: %10s\n'%(extType,extApprox))
2729                        text = ' Parameters       :'
2730                        for eKey in Ekey:
2731                            text += ' %4s : %10.3e Refine? '%(eKey,extParms[eKey][0])+str(extParms[eKey][1])
2732                        pFile.write(text+'\n')
2733                    if hapData['Babinet']['BabA'][0]:
2734                        PrintBabinet(hapData['Babinet'])
2735                    if not SGData['SGInv'] and len(Twins) == 1:
2736                        pFile.write(' Flack parameter: %10.3f Refine? %s\n'%(hapData['Flack'][0],hapData['Flack'][1]))
2737                    if len(Twins) > 1:
2738                        for it,twin in enumerate(Twins):
2739                            if 'bool' in str(type(twin[0])):
2740                                pFile.write(' Nonmerohedral twin fr.: %5.3f Inv? %s Refine? %s\n'%
2741                                    (hapDict[pfx+'TwinFr:'+str(it)],str(controlDict[pfx+'TwinInv'][it]),str(Twins[0][1][1])))
2742                            else:
2743                                pFile.write(' Twin law: %s Twin fr.: %5.3f Refine? %s\n'%
2744                                    (str(twin[0]).replace('\n',','),hapDict[pfx+'TwinFr:'+str(it)],str(Twins[0][1][1])))
2745                       
2746                Histogram['Reflection Lists'] = phase       
2747               
2748    return hapVary,hapDict,controlDict
2749   
2750def SetHistogramPhaseData(parmDict,sigDict,Phases,Histograms,FFtables,Print=True,pFile=None):
2751    'needs a doc string'
2752   
2753    def PrintSizeAndSig(hapData,sizeSig):
2754        line = '\n Size model:     %9s'%(hapData[0])
2755        refine = False
2756        if hapData[0] in ['isotropic','uniaxial']:
2757            line += ' equatorial:%12.5f'%(hapData[1][0])
2758            if sizeSig[0][0]:
2759                line += ', sig:%8.4f'%(sizeSig[0][0])
2760                refine = True
2761            if hapData[0] == 'uniaxial':
2762                line += ' axial:%12.4f'%(hapData[1][1])
2763                if sizeSig[0][1]:
2764                    refine = True
2765                    line += ', sig:%8.4f'%(sizeSig[0][1])
2766            line += ' LG mix coeff.:%12.4f'%(hapData[1][2])
2767            if sizeSig[0][2]:
2768                refine = True
2769                line += ', sig:%8.4f'%(sizeSig[0][2])
2770            if refine:
2771                pFile.write(line+'\n')
2772        else:
2773            line += ' LG mix coeff.:%12.4f'%(hapData[1][2])
2774            if sizeSig[0][2]:
2775                refine = True
2776                line += ', sig:%8.4f'%(sizeSig[0][2])
2777            Snames = ['S11','S22','S33','S12','S13','S23']
2778            ptlbls = ' name  :'
2779            ptstr =  ' value :'
2780            sigstr = ' sig   :'
2781            for i,name in enumerate(Snames):
2782                ptlbls += '%12s' % (name)
2783                ptstr += '%12.6f' % (hapData[4][i])
2784                if sizeSig[1][i]:
2785                    refine = True
2786                    sigstr += '%12.6f' % (sizeSig[1][i])
2787                else:
2788                    sigstr += 12*' '
2789            if refine:
2790                pFile.write(line+'\n')
2791                pFile.write(ptlbls+'\n')
2792                pFile.write(ptstr+'\n')
2793                pFile.write(sigstr+'\n')
2794       
2795    def PrintMuStrainAndSig(hapData,mustrainSig,SGData):
2796        line = '\n Mustrain model: %9s\n'%(hapData[0])
2797        refine = False
2798        if hapData[0] in ['isotropic','uniaxial']:
2799            line += ' equatorial:%12.1f'%(hapData[1][0])
2800            if mustrainSig[0][0]:
2801                line += ', sig:%8.1f'%(mustrainSig[0][0])
2802                refine = True
2803            if hapData[0] == 'uniaxial':
2804                line += ' axial:%12.1f'%(hapData[1][1])
2805                if mustrainSig[0][1]:
2806                     line += ', sig:%8.1f'%(mustrainSig[0][1])
2807            line += ' LG mix coeff.:%12.4f'%(hapData[1][2])
2808            if mustrainSig[0][2]:
2809                refine = True
2810                line += ', sig:%8.3f'%(mustrainSig[0][2])
2811            if refine:
2812                pFile.write(line+'\n')
2813        else:
2814            line += ' LG mix coeff.:%12.4f'%(hapData[1][2])
2815            if mustrainSig[0][2]:
2816                refine = True
2817                line += ', sig:%8.3f'%(mustrainSig[0][2])
2818            Snames = G2spc.MustrainNames(SGData)
2819            ptlbls = ' name  :'
2820            ptstr =  ' value :'
2821            sigstr = ' sig   :'
2822            for i,name in enumerate(Snames):
2823                ptlbls += '%12s' % (name)
2824                ptstr += '%12.1f' % (hapData[4][i])
2825                if mustrainSig[1][i]:
2826                    refine = True
2827                    sigstr += '%12.1f' % (mustrainSig[1][i])
2828                else:
2829                    sigstr += 12*' '
2830            if refine:
2831                pFile.write(line+'\n')
2832                pFile.write(ptlbls+'\n')
2833                pFile.write(ptstr+'\n')
2834                pFile.write(sigstr+'\n')
2835           
2836    def PrintHStrainAndSig(hapData,strainSig,SGData):
2837        Hsnames = G2spc.HStrainNames(SGData)
2838        ptlbls = ' name  :'
2839        ptstr =  ' value :'
2840        sigstr = ' sig   :'
2841        refine = False
2842        for i,name in enumerate(Hsnames):
2843            ptlbls += '%12s' % (name)
2844            ptstr += '%12.4g' % (hapData[0][i])
2845            if name in strainSig:
2846                refine = True
2847                sigstr += '%12.4g' % (strainSig[name])
2848            else:
2849                sigstr += 12*' '
2850        if refine:
2851            pFile.write('\n Hydrostatic/elastic strain:\n')
2852            pFile.write(ptlbls+'\n')
2853            pFile.write(ptstr+'\n')
2854            pFile.write(sigstr+'\n')
2855       
2856    def PrintSHPOAndSig(pfx,hapData,POsig):
2857        Tindx = 1.0
2858        Tvar = 0.0
2859        pFile.write('\n Spherical harmonics preferred orientation: Order: %d\n'%hapData[4])
2860        ptlbls = ' names :'
2861        ptstr =  ' values:'
2862        sigstr = ' sig   :'
2863        for item in hapData[5]:
2864            ptlbls += '%12s'%(item)
2865            ptstr += '%12.3f'%(hapData[5][item])
2866            l = 2.0*eval(item.strip('C'))[0]+1
2867            Tindx += hapData[5][item]**2/l
2868            if pfx+item in POsig:
2869                Tvar += (2.*hapData[5][item]*POsig[pfx+item]/l)**2
2870                sigstr += '%12.3f'%(POsig[pfx+item])
2871            else:
2872                sigstr += 12*' ' 
2873        pFile.write(ptlbls+'\n')
2874        pFile.write(ptstr+'\n')
2875        pFile.write(sigstr+'\n')
2876        pFile.write('\n Texture index J = %.3f(%d)\n'%(Tindx,int(1000*np.sqrt(Tvar))))
2877       
2878    def PrintExtAndSig(pfx,hapData,ScalExtSig):
2879        pFile.write('\n Single crystal extinction: Type: %s Approx: %s\n'%(hapData[0],hapData[1]))
2880        text = ''
2881        for item in hapData[2]:
2882            if pfx+item in ScalExtSig:
2883                text += '       %s: '%(item)
2884                text += '%12.2e'%(hapData[2][item][0])
2885                if pfx+item in ScalExtSig:
2886                    text += ' sig: %12.2e'%(ScalExtSig[pfx+item])
2887        pFile.write(text+'\n')   
2888       
2889    def PrintBabinetAndSig(pfx,hapData,BabSig):
2890        pFile.write('\n Babinet form factor modification:\n')
2891        ptlbls = ' names :'
2892        ptstr =  ' values:'
2893        sigstr = ' sig   :'
2894        for item in hapData:
2895            ptlbls += '%12s'%(item)
2896            ptstr += '%12.3f'%(hapData[item][0])
2897            if pfx+item in BabSig:
2898                sigstr += '%12.3f'%(BabSig[pfx+item])
2899            else:
2900                sigstr += 12*' ' 
2901        pFile.write(ptlbls+'\n')
2902        pFile.write(ptstr+'\n')
2903        pFile.write(sigstr+'\n')
2904       
2905    def PrintTwinsAndSig(pfx,twinData,TwinSig):
2906        pFile.write('\n Twin Law fractions :\n')
2907        ptlbls = ' names :'
2908        ptstr =  ' values:'
2909        sigstr = ' sig   :'
2910        for it,item in enumerate(twinData):
2911            ptlbls += '     twin #%d'%(it)
2912            if it:
2913                ptstr += '%12.3f'%(item[1])
2914            else:
2915                ptstr += '%12.3f'%(item[1][0])
2916            if pfx+'TwinFr:'+str(it) in TwinSig:
2917                sigstr += '%12.3f'%(TwinSig[pfx+'TwinFr:'+str(it)])
2918            else:
2919                sigstr += 12*' ' 
2920        pFile.write(ptlbls+'\n')
2921        pFile.write(ptstr+'\n')
2922        pFile.write(sigstr+'\n')
2923       
2924   
2925    PhFrExtPOSig = {}
2926    SizeMuStrSig = {}
2927    ScalExtSig = {}
2928    BabSig = {}
2929    TwinFrSig = {}
2930    wtFrSum = {}
2931    for phase in Phases:
2932        HistoPhase = Phases[phase]['Histograms']
2933        General = Phases[phase]['General']
2934        SGData = General['SGData']
2935        pId = Phases[phase]['pId']
2936        histoList = list(HistoPhase.keys())
2937        histoList.sort()
2938        for histogram in histoList:
2939            try:
2940                Histogram = Histograms[histogram]
2941            except KeyError:                       
2942                #skip if histogram not included e.g. in a sequential refinement
2943                continue
2944            if not Phases[phase]['Histograms'][histogram]['Use']:
2945                #skip if phase absent from this histogram
2946                continue
2947            hapData = HistoPhase[histogram]
2948            hId = Histogram['hId']
2949            pfx = str(pId)+':'+str(hId)+':'
2950            if hId not in wtFrSum:
2951                wtFrSum[hId] = 0.
2952            if 'PWDR' in histogram:
2953                for item in ['Scale','Extinction']:
2954                    hapData[item][0] = parmDict[pfx+item]
2955                    if pfx+item in sigDict and not parmDict[pfx+'LeBail']:
2956                        PhFrExtPOSig.update({pfx+item:sigDict[pfx+item],})
2957                wtFrSum[hId] += hapData['Scale'][0]*General['Mass']
2958                if hapData['Pref.Ori.'][0] == 'MD':
2959                    hapData['Pref.Ori.'][1] = parmDict[pfx+'MD']
2960                    if pfx+'MD' in sigDict and not parmDict[pfx+'LeBail']:
2961                        PhFrExtPOSig.update({pfx+'MD':sigDict[pfx+'MD'],})
2962                else:                           #'SH' spherical harmonics
2963                    for item in hapData['Pref.Ori.'][5]:
2964                        hapData['Pref.Ori.'][5][item] = parmDict[pfx+item]
2965                        if pfx+item in sigDict and not parmDict[pfx+'LeBail']:
2966                            PhFrExtPOSig.update({pfx+item:sigDict[pfx+item],})
2967                SizeMuStrSig.update({pfx+'Mustrain':[[0,0,0],[0 for i in range(len(hapData['Mustrain'][4]))]],
2968                    pfx+'Size':[[0,0,0],[0 for i in range(len(hapData['Size'][4]))]],
2969                    pfx+'HStrain':{}})                 
2970                for item in ['Mustrain','Size']:
2971                    hapData[item][1][2] = parmDict[pfx+item+';mx']
2972#                    hapData[item][1][2] = min(1.,max(0.,hapData[item][1][2]))
2973                    if pfx+item+';mx' in sigDict:
2974                        SizeMuStrSig[pfx+item][0][2] = sigDict[pfx+item+';mx']
2975                    if hapData[item][0] in ['isotropic','uniaxial']:                   
2976                        hapData[item][1][0] = parmDict[pfx+item+';i']
2977                        if item == 'Size':
2978                            hapData[item][1][0] = min(10.,max(0.001,hapData[item][1][0]))
2979                        if pfx+item+';i' in sigDict: 
2980                            SizeMuStrSig[pfx+item][0][0] = sigDict[pfx+item+';i']
2981                        if hapData[item][0] == 'uniaxial':
2982                            hapData[item][1][1] = parmDict[pfx+item+';a']
2983                            if item == 'Size':
2984                                hapData[item][1][1] = min(10.,max(0.001,hapData[item][1][1]))                       
2985                            if pfx+item+';a' in sigDict:
2986                                SizeMuStrSig[pfx+item][0][1] = sigDict[pfx+item+';a']
2987                    else:       #generalized for mustrain or ellipsoidal for size
2988                        Nterms = len(hapData[item][4])
2989                        for i in range(Nterms):
2990                            sfx = ';'+str(i)
2991                            hapData[item][4][i] = parmDict[pfx+item+sfx]
2992                            if pfx+item+sfx in sigDict:
2993                                SizeMuStrSig[pfx+item][1][i] = sigDict[pfx+item+sfx]
2994                names = G2spc.HStrainNames(SGData)
2995                for i,name in enumerate(names):
2996                    hapData['HStrain'][0][i] = parmDict[pfx+name]
2997                    if pfx+name in sigDict:
2998                        SizeMuStrSig[pfx+'HStrain'][name] = sigDict[pfx+name]
2999                if 'Layer Disp' in hapData:
3000                    hapData['Layer Disp'][0] = parmDict[pfx+'LayerDisp']
3001                    if pfx+'LayerDisp' in sigDict:
3002                        SizeMuStrSig[pfx+'LayerDisp'] = sigDict[pfx+'LayerDisp']
3003                if Phases[phase]['General']['Type'] != 'magnetic':
3004                    for name in ['BabA','BabU']:
3005                        hapData['Babinet'][name][0] = parmDict[pfx+name]
3006                        if pfx+name in sigDict and not parmDict[pfx+'LeBail']:
3007                            BabSig[pfx+name] = sigDict[pfx+name]               
3008               
3009            elif 'HKLF' in histogram:
3010                for item in ['Scale','Flack']:
3011                    if parmDict.get(pfx+item):
3012                        hapData[item][0] = parmDict[pfx+item]
3013                        if pfx+item in sigDict:
3014                            ScalExtSig[pfx+item] = sigDict[pfx+item]
3015                for item in ['Ep','Eg','Es']:
3016                    if parmDict.get(pfx+item):
3017                        hapData['Extinction'][2][item][0] = parmDict[pfx+item]
3018                        if pfx+item in sigDict:
3019                            ScalExtSig[pfx+item] = sigDict[pfx+item]
3020                for item in ['BabA','BabU']:
3021                    hapData['Babinet'][item][0] = parmDict[pfx+item]
3022                    if pfx+item in sigDict:
3023                        BabSig[pfx+item] = sigDict[pfx+item]
3024                if 'Twins' in hapData:
3025                    it = 1
3026                    sumTwFr = 0.
3027                    while True:
3028                        try:
3029                            hapData['Twins'][it][1] = parmDict[pfx+'TwinFr:'+str(it)]
3030                            if pfx+'TwinFr:'+str(it) in sigDict:
3031                                TwinFrSig[pfx+'TwinFr:'+str(it)] = sigDict[pfx+'TwinFr:'+str(it)]
3032                            if it:
3033                                sumTwFr += hapData['Twins'][it][1]
3034                            it += 1
3035                        except KeyError:
3036                            break
3037                    hapData['Twins'][0][1][0] = 1.-sumTwFr
3038
3039    if Print:
3040        for phase in Phases:
3041            HistoPhase = Phases[phase]['Histograms']
3042            General = Phases[phase]['General']
3043            SGData = General['SGData']
3044            pId = Phases[phase]['pId']
3045            histoList = list(HistoPhase.keys())
3046            histoList.sort()
3047            for histogram in histoList:
3048                try:
3049                    Histogram = Histograms[histogram]
3050                except KeyError:                       
3051                    #skip if histogram not included e.g. in a sequential refinement
3052                    continue
3053                hapData = HistoPhase[histogram]
3054                hId = Histogram['hId']
3055                Histogram['Residuals'][str(pId)+'::Name'] = phase
3056                pfx = str(pId)+':'+str(hId)+':'
3057                hfx = ':%s:'%(hId)
3058                if pfx+'Nref' not in Histogram['Residuals']:    #skip not used phase in histogram
3059                    continue
3060                pFile.write('\n Phase: %s in histogram: %s\n'%(phase,histogram))
3061                pFile.write(135*'='+'\n')
3062                if 'PWDR' in histogram:
3063                    pFile.write(' Final refinement RF, RF^2 = %.2f%%, %.2f%% on %d reflections\n'%
3064                        (Histogram['Residuals'][pfx+'Rf'],Histogram['Residuals'][pfx+'Rf^2'],Histogram['Residuals'][pfx+'Nref']))
3065                    pFile.write(' Durbin-Watson statistic = %.3f\n'%(Histogram['Residuals']['Durbin-Watson']))
3066                    pFile.write(' Bragg intensity sum = %.3g\n'%(Histogram['Residuals'][pfx+'sumInt']))
3067                   
3068                    if parmDict[pfx+'LeBail']:
3069                        pFile.write(' Performed LeBail extraction for phase %s in histogram %s\n'%(phase,histogram))
3070                    else:
3071                        if pfx+'Scale' in PhFrExtPOSig:
3072                            wtFr = hapData['Scale'][0]*General['Mass']/wtFrSum[hId]
3073                            sigwtFr = PhFrExtPOSig[pfx+'Scale']*wtFr/hapData['Scale'][0]
3074                            pFile.write(' Phase fraction  : %10.5f, sig %10.5f Weight fraction  : %8.5f, sig %10.5f\n'%
3075                                (hapData['Scale'][0],PhFrExtPOSig[pfx+'Scale'],wtFr,sigwtFr))
3076                        if pfx+'Extinction' in PhFrExtPOSig:
3077                            pFile.write(' Extinction coeff: %10.4f, sig %10.4f\n'%(hapData['Extinction'][0],PhFrExtPOSig[pfx+'Extinction']))
3078                        if hapData['Pref.Ori.'][0] == 'MD':
3079                            if pfx+'MD' in PhFrExtPOSig:
3080                                pFile.write(' March-Dollase PO: %10.4f, sig %10.4f\n'%(hapData['Pref.Ori.'][1],PhFrExtPOSig[pfx+'MD']))
3081                        else:
3082                            PrintSHPOAndSig(pfx,hapData['Pref.Ori.'],PhFrExtPOSig)
3083                    PrintSizeAndSig(hapData['Size'],SizeMuStrSig[pfx+'Size'])
3084                    PrintMuStrainAndSig(hapData['Mustrain'],SizeMuStrSig[pfx+'Mustrain'],SGData)
3085                    PrintHStrainAndSig(hapData['HStrain'],SizeMuStrSig[pfx+'HStrain'],SGData)
3086                    if pfx+'LayerDisp' in SizeMuStrSig:
3087                        pFile.write(' Layer displacement : %10.3f, sig %10.3f\n'%(hapData['Layer Disp'][0],SizeMuStrSig[pfx+'LayerDisp']))           
3088                    if Phases[phase]['General']['Type'] != 'magnetic' and not parmDict[pfx+'LeBail']:
3089                        if len(BabSig):
3090                            PrintBabinetAndSig(pfx,hapData['Babinet'],BabSig)
3091                   
3092                elif 'HKLF' in histogram:
3093                    Inst = Histogram['Instrument Parameters'][0]
3094                    pFile.write(' Final refinement RF, RF^2 = %.2f%%, %.2f%% on %d reflections (%d user rejected, %d sp.gp.extinct)\n'%
3095                        (Histogram['Residuals'][pfx+'Rf'],Histogram['Residuals'][pfx+'Rf^2'],Histogram['Residuals'][pfx+'Nref'],
3096                        Histogram['Residuals'][pfx+'Nrej'],Histogram['Residuals'][pfx+'Next']))
3097                    if FFtables != None and 'N' not in Inst['Type'][0]:
3098                        PrintFprime(FFtables,hfx,pFile)
3099                    pFile.write(' HKLF histogram weight factor = %.3f\n'%(Histogram['wtFactor']))
3100                    if pfx+'Scale' in ScalExtSig:
3101                        pFile.write(' Scale factor : %10.4f, sig %10.4f\n'%(hapData['Scale'][0],ScalExtSig[pfx+'Scale']))
3102                    if hapData['Extinction'][0] != 'None':
3103                        PrintExtAndSig(pfx,hapData['Extinction'],ScalExtSig)
3104                    if len(BabSig):
3105                        PrintBabinetAndSig(pfx,hapData['Babinet'],BabSig)
3106                    if pfx+'Flack' in ScalExtSig:
3107                        pFile.write(' Flack parameter : %10.3f, sig %10.3f\n'%(hapData['Flack'][0],ScalExtSig[pfx+'Flack']))
3108                    if len(TwinFrSig):
3109                        PrintTwinsAndSig(pfx,hapData['Twins'],TwinFrSig)
3110
3111################################################################################
3112##### Histogram data
3113################################################################################       
3114                   
3115def GetHistogramData(Histograms,Print=True,pFile=None):
3116    'needs a doc string'
3117   
3118    def GetBackgroundParms(hId,Background):
3119        Back = Background[0]
3120        DebyePeaks = Background[1]
3121        bakType,bakFlag = Back[:2]
3122        backVals = Back[3:]
3123        backNames = [':'+str(hId)+':Back;'+str(i) for i in range(len(backVals))]
3124        backDict = dict(zip(backNames,backVals))
3125        backVary = []
3126        if bakFlag:
3127            backVary = backNames
3128        backDict[':'+str(hId)+':nDebye'] = DebyePeaks['nDebye']
3129        backDict[':'+str(hId)+':nPeaks'] = DebyePeaks['nPeaks']
3130        debyeDict = {}
3131        debyeList = []
3132        for i in range(DebyePeaks['nDebye']):
3133            debyeNames = [':'+str(hId)+':DebyeA;'+str(i),':'+str(hId)+':DebyeR;'+str(i),':'+str(hId)+':DebyeU;'+str(i)]
3134            debyeDict.update(dict(zip(debyeNames,DebyePeaks['debyeTerms'][i][::2])))
3135            debyeList += zip(debyeNames,DebyePeaks['debyeTerms'][i][1::2])
3136        debyeVary = []
3137        for item in debyeList:
3138            if item[1]:
3139                debyeVary.append(item[0])
3140        backDict.update(debyeDict)
3141        backVary += debyeVary
3142        peakDict = {}
3143        peakList = []
3144        for i in range(DebyePeaks['nPeaks']):
3145            peakNames = [':'+str(hId)+':BkPkpos;'+str(i),':'+str(hId)+ \
3146                ':BkPkint;'+str(i),':'+str(hId)+':BkPksig;'+str(i),':'+str(hId)+':BkPkgam;'+str(i)]
3147            peakDict.update(dict(zip(peakNames,DebyePeaks['peaksList'][i][::2])))
3148            peakList += zip(peakNames,DebyePeaks['peaksList'][i][1::2])
3149        peakVary = []
3150        for item in peakList:
3151            if item[1]:
3152                peakVary.append(item[0])
3153        backDict.update(peakDict)
3154        backVary += peakVary
3155        return bakType,backDict,backVary           
3156       
3157    def GetInstParms(hId,Inst):
3158        #patch
3159        if 'Z' not in Inst:
3160            Inst['Z'] = [0.0,0.0,False]
3161        dataType = Inst['Type'][0]
3162        instDict = {}
3163        insVary = []
3164        pfx = ':'+str(hId)+':'
3165        insKeys = list(Inst.keys())
3166        insKeys.sort()
3167        for item in insKeys:
3168            if item in 'Azimuth':
3169                continue
3170            insName = pfx+item
3171            instDict[insName] = Inst[item][1]
3172            if len(Inst[item]) > 2 and Inst[item][2]:
3173                insVary.append(insName)
3174        if 'C' in dataType:
3175            instDict[pfx+'SH/L'] = max(instDict[pfx+'SH/L'],0.0005)
3176        elif 'T' in dataType:   #trap zero alp, bet coeff.
3177            if not instDict[pfx+'alpha']:
3178                instDict[pfx+'alpha'] = 1.0
3179            if not instDict[pfx+'beta-0'] and not instDict[pfx+'beta-1']:
3180                instDict[pfx+'beta-1'] = 1.0
3181        elif 'B' in dataType:   #trap zero alp, bet coeff.
3182            if not instDict[pfx+'alpha-0'] and not instDict[pfx+'alpha-1']:
3183                instDict[pfx+'alpha-1'] = 1.0
3184            if not instDict[pfx+'beta-0'] and not instDict[pfx+'beta-1']:
3185                instDict[pfx+'beta-1'] = 1.0
3186        return dataType,instDict,insVary
3187       
3188    def GetSampleParms(hId,Sample):
3189        sampVary = []
3190        hfx = ':'+str(hId)+':'       
3191        sampDict = {hfx+'Gonio. radius':Sample['Gonio. radius'],hfx+'Omega':Sample['Omega'],
3192            hfx+'Chi':Sample['Chi'],hfx+'Phi':Sample['Phi'],hfx+'Azimuth':Sample['Azimuth']}
3193        for key in ('Temperature','Pressure','FreePrm1','FreePrm2','FreePrm3'):
3194            if key in Sample:
3195                sampDict[hfx+key] = Sample[key]
3196        Type = Sample['Type']
3197        if 'Bragg' in Type:             #Bragg-Brentano
3198            for item in ['Scale','Shift','Transparency','SurfRoughA','SurfRoughB']:
3199                sampDict[hfx+item] = Sample[item][0]
3200                if Sample[item][1]:
3201                    sampVary.append(hfx+item)
3202        elif 'Debye' in Type:        #Debye-Scherrer
3203            for item in ['Scale','Absorption','DisplaceX','DisplaceY']:
3204                sampDict[hfx+item] = Sample[item][0]
3205                if Sample[item][1]:
3206                    sampVary.append(hfx+item)
3207        return Type,sampDict,sampVary
3208       
3209    def PrintBackground(Background):
3210        Back = Background[0]
3211        DebyePeaks = Background[1]
3212        pFile.write('\n Background function: %s Refine? %s\n'%(Back[0],Back[1]))
3213        line = ' Coefficients: '
3214        for i,back in enumerate(Back[3:]):
3215            line += '%10.3f'%(back)
3216            if i and not i%10:
3217                line += '\n'+15*' '
3218        pFile.write(line+'\n')
3219        if DebyePeaks['nDebye']:
3220            pFile.write('\n Debye diffuse scattering coefficients\n')
3221            parms = ['DebyeA','DebyeR','DebyeU']
3222            line = ' names :  '
3223            for parm in parms:
3224                line += '%8s refine?'%(parm)
3225            pFile.write(line+'\n')
3226            for j,term in enumerate(DebyePeaks['debyeTerms']):
3227                line = ' term'+'%2d'%(j)+':'
3228                for i in range(3):
3229                    line += '%10.3f %5s'%(term[2*i],bool(term[2*i+1]))                   
3230                pFile.write(line+'\n')
3231        if DebyePeaks['nPeaks']:
3232            pFile.write('\n Single peak coefficients\n')
3233            parms =    ['BkPkpos','BkPkint','BkPksig','BkPkgam']
3234            line = ' names :  '
3235            for parm in parms:
3236                line += '%8s refine?'%(parm)
3237            pFile.write(line+'\n')
3238            for j,term in enumerate(DebyePeaks['peaksList']):
3239                line = ' peak'+'%2d'%(j)+':'
3240                for i in range(4):
3241                    line += '%12.3f %5s'%(term[2*i],bool(term[2*i+1]))                   
3242                pFile.write(line+'\n')
3243       
3244    def PrintInstParms(Inst):
3245        pFile.write('\n Instrument Parameters:\n')
3246        insKeys = list(Inst.keys())
3247        insKeys.sort()
3248        iBeg = 0
3249        Ok = True
3250        while Ok:
3251            ptlbls = ' name  :'
3252            ptstr =  ' value :'
3253            varstr = ' refine:'
3254            iFin = min(iBeg+9,len(insKeys))
3255            for item in insKeys[iBeg:iFin]:
3256                if item not in ['Type','Source']:
3257                    ptlbls += '%12s' % (item)
3258                    ptstr += '%12.6f' % (Inst[item][1])
3259                    if item in ['Lam1','Lam2','Azimuth','fltPath','2-theta',]:
3260                        varstr += 12*' '
3261                    else:
3262                        varstr += '%12s' % (str(bool(Inst[item][2])))
3263            pFile.write(ptlbls+'\n')
3264            pFile.write(ptstr+'\n')
3265            pFile.write(varstr+'\n')
3266            iBeg = iFin
3267            if iBeg == len(insKeys):
3268                Ok = False
3269            else:
3270                pFile.write('\n')
3271       
3272    def PrintSampleParms(Sample):
3273        pFile.write('\n Sample Parameters:\n')
3274        pFile.write(' Goniometer omega = %.2f, chi = %.2f, phi = %.2f\n'%
3275            (Sample['Omega'],Sample['Chi'],Sample['Phi']))
3276        ptlbls = ' name  :'
3277        ptstr =  ' value :'
3278        varstr = ' refine:'
3279        if 'Bragg' in Sample['Type']:
3280            for item in ['Scale','Shift','Transparency','SurfRoughA','SurfRoughB']:
3281                ptlbls += '%14s'%(item)
3282                ptstr += '%14.4f'%(Sample[item][0])
3283                varstr += '%14s'%(str(bool(Sample[item][1])))
3284           
3285        elif 'Debye' in Type:        #Debye-Scherrer
3286            for item in ['Scale','Absorption','DisplaceX','DisplaceY']:
3287                ptlbls += '%14s'%(item)
3288                ptstr += '%14.4f'%(Sample[item][0])
3289                varstr += '%14s'%(str(bool(Sample[item][1])))
3290
3291        pFile.write(ptlbls+'\n')
3292        pFile.write(ptstr+'\n')
3293        pFile.write(varstr+'\n')
3294       
3295    histDict = {}
3296    histVary = []
3297    controlDict = {}
3298    histoList = list(Histograms.keys())
3299    histoList.sort()
3300    for histogram in histoList:
3301        if 'PWDR' in histogram:
3302            Histogram = Histograms[histogram]
3303            hId = Histogram['hId']
3304            pfx = ':'+str(hId)+':'
3305            controlDict[pfx+'wtFactor'] = Histogram['wtFactor']
3306            controlDict[pfx+'Limits'] = Histogram['Limits'][1]
3307            controlDict[pfx+'Exclude'] = Histogram['Limits'][2:]
3308            for excl in controlDict[pfx+'Exclude']:
3309                Histogram['Data'][0] = ma.masked_inside(Histogram['Data'][0],excl[0],excl[1])
3310            if controlDict[pfx+'Exclude']:
3311                ma.mask_rows(Histogram['Data'])
3312            Background = Histogram['Background']
3313            Type,bakDict,bakVary = GetBackgroundParms(hId,Background)
3314            controlDict[pfx+'bakType'] = Type
3315            histDict.update(bakDict)
3316            histVary += bakVary
3317           
3318            Inst = Histogram['Instrument Parameters']        #TODO ? ignores tabulated alp,bet & delt for TOF
3319            if 'T' in Type and len(Inst[1]):    #patch -  back-to-back exponential contribution to TOF line shape is removed
3320                G2fil.G2Print ('Warning: tabulated profile coefficients are ignored')
3321            Type,instDict,insVary = GetInstParms(hId,Inst[0])
3322            controlDict[pfx+'histType'] = Type
3323            if 'XC' in Type or 'XB' in Type:
3324                if pfx+'Lam1' in instDict:
3325                    controlDict[pfx+'keV'] = 12.397639/instDict[pfx+'Lam1']
3326                else:
3327                    controlDict[pfx+'keV'] = 12.397639/instDict[pfx+'Lam']           
3328            histDict.update(instDict)
3329            histVary += insVary
3330           
3331            Sample = Histogram['Sample Parameters']
3332            Type,sampDict,sampVary = GetSampleParms(hId,Sample)
3333            controlDict[pfx+'instType'] = Type
3334            histDict.update(sampDict)
3335            histVary += sampVary
3336           
3337   
3338            if Print: 
3339                pFile.write('\n Histogram: %s histogram Id: %d\n'%(histogram,hId))
3340                pFile.write(135*'='+'\n')
3341                Units = {'C':' deg','T':' msec','B':' deg'}
3342                units = Units[controlDict[pfx+'histType'][2]]
3343                Limits = controlDict[pfx+'Limits']
3344                pFile.write(' Instrument type: %s\n'%Sample['Type'])
3345                pFile.write(' Histogram limits: %8.2f%s to %8.2f%s\n'%(Limits[0],units,Limits[1],units))
3346                if len(controlDict[pfx+'Exclude']):
3347                    excls = controlDict[pfx+'Exclude']
3348                    for excl in excls:
3349                        pFile.write(' Excluded region:  %8.2f%s to %8.2f%s\n'%(excl[0],units,excl[1],units)) 
3350                PrintSampleParms(Sample)
3351                PrintInstParms(Inst[0])
3352                PrintBackground(Background)
3353        elif 'HKLF' in histogram:
3354            Histogram = Histograms[histogram]
3355            hId = Histogram['hId']
3356            pfx = ':'+str(hId)+':'
3357            controlDict[pfx+'wtFactor'] = Histogram['wtFactor']
3358            Inst = Histogram['Instrument Parameters'][0]
3359            controlDict[pfx+'histType'] = Inst['Type'][0]
3360            if 'X' in Inst['Type'][0]:
3361                histDict[pfx+'Lam'] = Inst['Lam'][1]
3362                controlDict[pfx+'keV'] = 12.397639/histDict[pfx+'Lam']
3363            elif 'NC' in Inst['Type'][0] or 'NB' in Inst['Type'][0]:                   
3364                histDict[pfx+'Lam'] = Inst['Lam'][1]
3365    return histVary,histDict,controlDict
3366   
3367def SetHistogramData(parmDict,sigDict,Histograms,FFtables,Print=True,pFile=None,seq=False):
3368    'Shows histogram data after a refinement'
3369   
3370    def SetBackgroundParms(pfx,Background,parmDict,sigDict):
3371        Back = Background[0]
3372        DebyePeaks = Background[1]
3373        lenBack = len(Back[3:])
3374        backSig = [0 for i in range(lenBack+3*DebyePeaks['nDebye']+4*DebyePeaks['nPeaks'])]
3375        for i in range(lenBack):
3376            Back[3+i] = parmDict[pfx+'Back;'+str(i)]
3377            if pfx+'Back;'+str(i) in sigDict:
3378                backSig[i] = sigDict[pfx+'Back;'+str(i)]
3379        if DebyePeaks['nDebye']:
3380            for i in range(DebyePeaks['nDebye']):
3381                names = [pfx+'DebyeA;'+str(i),pfx+'DebyeR;'+str(i),pfx+'DebyeU;'+str(i)]
3382                for j,name in enumerate(names):
3383                    DebyePeaks['debyeTerms'][i][2*j] = parmDict[name]
3384                    if name in sigDict:
3385                        backSig[lenBack+3*i+j] = sigDict[name]           
3386        if DebyePeaks['nPeaks']:
3387            for i in range(DebyePeaks['nPeaks']):
3388                names = [pfx+'BkPkpos;'+str(i),pfx+'BkPkint;'+str(i),
3389                    pfx+'BkPksig;'+str(i),pfx+'BkPkgam;'+str(i)]
3390                for j,name in enumerate(names):
3391                    DebyePeaks['peaksList'][i][2*j] = parmDict[name]
3392                    if name in sigDict:
3393                        backSig[lenBack+3*DebyePeaks['nDebye']+4*i+j] = sigDict[name]
3394        return backSig
3395       
3396    def SetInstParms(pfx,Inst,parmDict,sigDict):
3397        instSig = {}
3398        insKeys = list(Inst.keys())
3399        insKeys.sort()
3400        for item in insKeys:
3401            insName = pfx+item
3402            Inst[item][1] = parmDict[insName]
3403            if insName in sigDict:
3404                instSig[item] = sigDict[insName]
3405            else:
3406                instSig[item] = 0
3407        return instSig
3408       
3409    def SetSampleParms(pfx,Sample,parmDict,sigDict):
3410        if 'Bragg' in Sample['Type']:             #Bragg-Brentano
3411            sampSig = [0 for i in range(5)]
3412            for i,item in enumerate(['Scale','Shift','Transparency','SurfRoughA','SurfRoughB']):
3413                Sample[item][0] = parmDict[pfx+item]
3414                if pfx+item in sigDict:
3415                    sampSig[i] = sigDict[pfx+item]
3416        elif 'Debye' in Sample['Type']:        #Debye-Scherrer
3417            sampSig = [0 for i in range(4)]
3418            for i,item in enumerate(['Scale','Absorption','DisplaceX','DisplaceY']):
3419                Sample[item][0] = parmDict[pfx+item]
3420                if pfx+item in sigDict:
3421                    sampSig[i] = sigDict[pfx+item]
3422        return sampSig
3423       
3424    def PrintBackgroundSig(Background,backSig):
3425        Back = Background[0]
3426        DebyePeaks = Background[1]
3427        valstr = ' value : '
3428        sigstr = ' sig   : '
3429        refine = False
3430        for i,back in enumerate(Back[3:]):
3431            valstr += '%10.4g'%(back)
3432            if Back[1]:
3433                refine = True
3434                sigstr += '%10.4g'%(backSig[i])
3435            else:
3436                sigstr += 10*' '
3437        if refine:
3438            pFile.write('\n Background function: %s\n'%Back[0])
3439            pFile.write(valstr+'\n')
3440            pFile.write(sigstr+'\n')
3441        if DebyePeaks['nDebye']:
3442            ifAny = False
3443            ptfmt = "%12.3f"
3444            names =  ' names :'
3445            ptstr =  ' values:'
3446            sigstr = ' esds  :'
3447            for item in sigDict:
3448                if 'Debye' in item:
3449                    ifAny = True
3450                    names += '%12s'%(item)
3451                    ptstr += ptfmt%(parmDict[item])
3452                    sigstr += ptfmt%(sigDict[item])
3453            if ifAny:
3454                pFile.write('\n Debye diffuse scattering coefficients\n')
3455                pFile.write(names+'\n')
3456                pFile.write(ptstr+'\n')
3457                pFile.write(sigstr+'\n')
3458        if DebyePeaks['nPeaks']:
3459            pFile.write('\n Single peak coefficients:\n')
3460            parms =    ['BkPkpos','BkPkint','BkPksig','BkPkgam']
3461            line = ' peak no. '
3462            for parm in parms:
3463                line += '%14s%12s'%(parm.center(14),'esd'.center(12))
3464            pFile.write(line+'\n')
3465            for ip in range(DebyePeaks['nPeaks']):
3466                ptstr = ' %4d '%(ip)
3467                for parm in parms:
3468                    fmt = '%14.3f'
3469                    efmt = '%12.3f'
3470                    if parm == 'BkPkpos':
3471                        fmt = '%14.4f'
3472                        efmt = '%12.4f'
3473                    name = pfx+parm+';%d'%(ip)
3474                    ptstr += fmt%(parmDict[name])
3475                    if name in sigDict:
3476                        ptstr += efmt%(sigDict[name])
3477                    else:
3478                        ptstr += 12*' '
3479                pFile.write(ptstr+'\n')
3480        sumBk = np.array(Histogram['sumBk'])
3481        pFile.write(' Background sums: empirical %.3g, Debye %.3g, peaks %.3g, Total %.3g\n'%
3482            (sumBk[0],sumBk[1],sumBk[2],np.sum(sumBk)))
3483       
3484    def PrintInstParmsSig(Inst,instSig):
3485        refine = False
3486        insKeys = list(instSig.keys())
3487        insKeys.sort()
3488        iBeg = 0
3489        Ok = True
3490        while Ok:
3491            ptlbls = ' names :'
3492            ptstr =  ' value :'
3493            sigstr = ' sig   :'
3494            iFin = min(iBeg+9,len(insKeys))
3495            for name in insKeys[iBeg:iFin]:
3496                if name not in  ['Type','Lam1','Lam2','Azimuth','Source','fltPath']:
3497                    ptlbls += '%12s' % (name)
3498                    ptstr += '%12.6f' % (Inst[name][1])
3499                    if instSig[name]:
3500                        refine = True
3501                        sigstr += '%12.6f' % (instSig[name])
3502                    else:
3503                        sigstr += 12*' '
3504            if refine:
3505                pFile.write('\n Instrument Parameters:\n')
3506                pFile.write(ptlbls+'\n')
3507                pFile.write(ptstr+'\n')
3508                pFile.write(sigstr+'\n')
3509            iBeg = iFin
3510            if iBeg == len(insKeys):
3511                Ok = False
3512       
3513    def PrintSampleParmsSig(Sample,sampleSig):
3514        ptlbls = ' names :'
3515        ptstr =  ' values:'
3516        sigstr = ' sig   :'
3517        refine = False
3518        if 'Bragg' in Sample['Type']:
3519            for i,item in enumerate(['Scale','Shift','Transparency','SurfRoughA','SurfRoughB']):
3520                ptlbls += '%14s'%(item)
3521                ptstr += '%14.4f'%(Sample[item][0])
3522                if sampleSig[i]:
3523                    refine = True
3524                    sigstr += '%14.4f'%(sampleSig[i])
3525                else:
3526                    sigstr += 14*' '
3527           
3528        elif 'Debye' in Sample['Type']:        #Debye-Scherrer
3529            for i,item in enumerate(['Scale','Absorption','DisplaceX','DisplaceY']):
3530                ptlbls += '%14s'%(item)
3531                ptstr += '%14.4f'%(Sample[item][0])
3532                if sampleSig[i]:
3533                    refine = True
3534                    sigstr += '%14.4f'%(sampleSig[i])
3535                else:
3536                    sigstr += 14*' '
3537
3538        if refine:
3539            pFile.write('\n Sample Parameters:\n')
3540            pFile.write(ptlbls+'\n')
3541            pFile.write(ptstr+'\n')
3542            pFile.write(sigstr+'\n')
3543       
3544    histoList = list(Histograms.keys())
3545    histoList.sort()
3546    for histogram in histoList:
3547        if 'PWDR' in histogram:
3548            Histogram = Histograms[histogram]
3549            hId = Histogram['hId']
3550            pfx = ':'+str(hId)+':'
3551            Background = Histogram['Background']
3552            backSig = SetBackgroundParms(pfx,Background,parmDict,sigDict)
3553           
3554            Inst = Histogram['Instrument Parameters'][0]
3555            instSig = SetInstParms(pfx,Inst,parmDict,sigDict)
3556       
3557            Sample = Histogram['Sample Parameters']
3558            sampSig = SetSampleParms(pfx,Sample,parmDict,sigDict)
3559
3560            if not seq:
3561                pFile.write('\n Histogram: %s histogram Id: %d\n'%(histogram,hId))
3562                pFile.write(135*'='+'\n')
3563            pFile.write(' PWDR histogram weight factor = '+'%.3f\n'%(Histogram['wtFactor']))
3564            pFile.write(' Final refinement wR = %.2f%% on %d observations in this histogram\n'%
3565                (Histogram['Residuals']['wR'],Histogram['Residuals']['Nobs']))
3566            pFile.write(' Other residuals: R = %.2f%%, R-bkg = %.2f%%, wR-bkg = %.2f%% wRmin = %.2f%%\n'%
3567                (Histogram['Residuals']['R'],Histogram['Residuals']['Rb'],Histogram['Residuals']['wR'],Histogram['Residuals']['wRmin']))
3568            if Print:
3569                pFile.write(' Instrument type: %s\n'%Sample['Type'])
3570                if FFtables != None and 'N' not in Inst['Type'][0]:
3571                    PrintFprime(FFtables,pfx,pFile)
3572                PrintSampleParmsSig(Sample,sampSig)
3573                PrintInstParmsSig(Inst,instSig)
3574                PrintBackgroundSig(Background,backSig)
3575               
3576def WriteRBObjPOAndSig(pfx,rbfx,rbsx,parmDict,sigDict):
3577    '''Cribbed version of PrintRBObjPOAndSig but returns lists of strings.
3578    Moved so it can be used in ExportCIF
3579    '''
3580    namstr = '  names :'
3581    valstr = '  values:'
3582    sigstr = '  esds  :'
3583    for i,px in enumerate(['Px:','Py:','Pz:']):
3584        name = pfx+rbfx+px+rbsx
3585        namstr += '%12s'%('Pos '+px[1])
3586        valstr += '%12.5f'%(parmDict[name])
3587        if name in sigDict:
3588            sigstr += '%12.5f'%(sigDict[name])
3589        else:
3590            sigstr += 12*' '
3591    for i,po in enumerate(['Oa:','Oi:','Oj:','Ok:']):
3592        name = pfx+rbfx+po+rbsx
3593        namstr += '%12s'%('Ori '+po[1])
3594        valstr += '%12.5f'%(parmDict[name])
3595        if name in sigDict:
3596            sigstr += '%12.5f'%(sigDict[name])
3597        else:
3598            sigstr += 12*' '
3599    return (namstr,valstr,sigstr)
3600
3601def WriteRBObjTLSAndSig(pfx,rbfx,rbsx,TLS,parmDict,sigDict):
3602    '''Cribbed version of PrintRBObjTLSAndSig but returns lists of strings.
3603    Moved so it can be used in ExportCIF
3604    '''
3605    out = []
3606    namstr = '  names :'
3607    valstr = '  values:'
3608    sigstr = '  esds  :'
3609    if 'N' not in TLS:
3610        out.append(' Thermal motion:\n')
3611    if 'T' in TLS:
3612        for i,pt in enumerate(['T11:','T22:','T33:','T12:','T13:','T23:']):
3613            name = pfx+rbfx+pt+rbsx
3614            namstr += '%12s'%(pt[:3])
3615            valstr += '%12.5f'%(parmDict[name])
3616            if name in sigDict:
3617                sigstr += '%12.5f'%(sigDict[name])
3618            else:
3619                sigstr += 12*' '
3620        out.append(namstr+'\n')
3621        out.append(valstr+'\n')
3622        out.append(sigstr+'\n')
3623    if 'L' in TLS:
3624        namstr = '  names :'
3625        valstr = '  values:'
3626        sigstr = '  esds  :'
3627        for i,pt in enumerate(['L11:','L22:','L33:','L12:','L13:','L23:']):
3628            name = pfx+rbfx+pt+rbsx
3629            namstr += '%12s'%(pt[:3])
3630            valstr += '%12.3f'%(parmDict[name])
3631            if name in sigDict:
3632                sigstr += '%12.3f'%(sigDict[name])
3633            else:
3634                sigstr += 12*' '
3635        out.append(namstr+'\n')
3636        out.append(valstr+'\n')
3637        out.append(sigstr+'\n')
3638    if 'S' in TLS:
3639        namstr = '  names :'
3640        valstr = '  values:'
3641        sigstr = '  esds  :'
3642        for i,pt in enumerate(['S12:','S13:','S21:','S23:','S31:','S32:','SAA:','SBB:']):
3643            name = pfx+rbfx+pt+rbsx
3644            namstr += '%12s'%(pt[:3])
3645            valstr += '%12.4f'%(parmDict[name])
3646            if name in sigDict:
3647                sigstr += '%12.4f'%(sigDict[name])
3648            else:
3649                sigstr += 12*' '
3650        out.append(namstr+'\n')
3651        out.append(valstr+'\n')
3652        out.append(sigstr+'\n')
3653    if 'U' in TLS:
3654        name = pfx+rbfx+'U:'+rbsx
3655        namstr = '  names :'+'%12s'%('Uiso')
3656        valstr = '  values:'+'%12.5f'%(parmDict[name])
3657        if name in sigDict:
3658            sigstr = '  esds  :'+'%12.5f'%(sigDict[name])
3659        else:
3660            sigstr = '  esds  :'+12*' '
3661        out.append(namstr+'\n')
3662        out.append(valstr+'\n')
3663        out.append(sigstr+'\n')
3664    return out
3665
3666def WriteRBObjTorAndSig(pfx,rbsx,parmDict,sigDict,nTors):
3667    '''Cribbed version of PrintRBObjTorAndSig but returns lists of strings.
3668    Moved so it can be used in ExportCIF
3669    '''
3670    out = []
3671    namstr = '  names :'
3672    valstr = '  values:'
3673    sigstr = '  esds  :'
3674    out.append(' Torsions:\n')
3675    for it in range(nTors):
3676        name = pfx+'RBRTr;'+str(it)+':'+rbsx
3677        namstr += '%12s'%('Tor'+str(it))
3678        valstr += '%12.4f'%(parmDict[name])
3679        if name in sigDict:
3680            sigstr += '%12.4f'%(sigDict[name])
3681    out.append(namstr+'\n')
3682    out.append(valstr+'\n')
3683    out.append(sigstr+'\n')
3684    return out
3685
3686def WriteResRBModel(RBModel):
3687    '''Write description of a residue rigid body. Code shifted from
3688    PrintResRBModel to make usable from G2export_CIF
3689    '''
3690    out = []
3691    atNames = RBModel['atNames']
3692    rbRef = RBModel['rbRef']
3693    rbSeq = RBModel['rbSeq']
3694    out.append('    At name       x          y          z\n')
3695    for name,xyz in zip(atNames,RBModel['rbXYZ']):
3696        out.append(%8s %10.4f %10.4f %10.4f\n'%(name,xyz[0],xyz[1],xyz[2]))
3697    out.append('  Orientation defined by: %s -> %s & %s -> %s\n'%
3698        (atNames[rbRef[0]],atNames[rbRef[1]],atNames[rbRef[0]],atNames[rbRef[2]]))
3699    if rbSeq:
3700        for i,rbseq in enumerate(rbSeq):
3701#                nameLst = [atNames[i] for i in rbseq[3]]
3702            out.append('  Torsion sequence %d Bond: %s - %s riding: %s\n'%
3703                    (i,atNames[rbseq[0]],atNames[rbseq[1]],str([atNames[i] for i in rbseq[3]])))
3704    return out
3705
3706def WriteVecRBModel(RBModel,sigDict={},irb=None):
3707    '''Write description of a vector rigid body. Code shifted from
3708    PrintVecRBModel to make usable from G2export_CIF
3709    '''
3710    out = []
3711    rbRef = RBModel['rbRef']
3712    atTypes = RBModel['rbTypes']
3713    for i in range(len(RBModel['VectMag'])):
3714        if sigDict and irb is not None:
3715            name = '::RBV;'+str(i)+':'+str(irb)
3716            s = G2mth.ValEsd(RBModel['VectMag'][i],sigDict.get(name,-.0001))
3717            out.append('Vector no.: %d Magnitude: %s\n'%(i,s))
3718        else:
3719            out.append('Vector no.: %d Magnitude: %8.4f Refine? %s\n'%
3720                           (i,RBModel['VectMag'][i],RBModel['VectRef'][i]))
3721        out.append('  No. Type     vx         vy         vz\n')
3722        for j,[name,xyz] in enumerate(zip(atTypes,RBModel['rbVect'][i])):
3723            out.append(%d   %2s %10.4f %10.4f %10.4f\n'%(j,name,xyz[0],xyz[1],xyz[2]))
3724    out.append('  No. Type      x          y          z\n')
3725    for i,[name,xyz] in enumerate(zip(atTypes,RBModel['rbXYZ'])):
3726        out.append(%d   %2s %10.4f %10.4f %10.4f\n'%(i,name,xyz[0],xyz[1],xyz[2]))
3727    return out
Note: See TracBrowser for help on using the repository browser.