source: trunk/GSASIIstrIO.py @ 5038

Last change on this file since 5038 was 5038, checked in by toby, 2 years ago

Major revision to constraints including an update to the Sequential Refinement tutorial

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