source: trunk/GSASIIstrIO.py @ 4824

Last change on this file since 4824 was 4824, checked in by vondreele, 2 years ago

add new refinable RB parameter for atom site fraction - always there; can be used in constraints.. Available for residue & vector style RBs
fixes to delete RB routines
fixes to RB naming when adding RB to structure
Implement use of view position for new RB origin

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