Changeset 5042


Ignore:
Timestamp:
Oct 4, 2021 5:14:24 PM (8 months ago)
Author:
toby
Message:

implement sequential CIF export; minor CIF bug fixes; add su to seq res for WtFrac?; Add new sequential project export menu items; move some lattice labels to G2lat; Use G2strIO (not G2strIO) throughout

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIIO.py

    r5038 r5042  
    17221722          If an extension is supplied, it is not overridded,
    17231723          but if not, the default extension is used.
     1724        :param str mode:  The mode can 'w' to write a file, or 'a' to append to it. If
     1725          the mode is 'd' (for debug), output is displayed on the console.
    17241726        :returns: the file object opened by the routine which is also
    17251727          saved as self.fp
     
    19501952        print('No Export routine supports extension '+extension)
    19511953
     1954def ExportSequentialFullCIF(G2frame,seqData,Controls):
     1955    '''Handles access to CIF exporter a bit differently for sequential fits, as this is
     1956    not accessed via the usual export menus
     1957    '''
     1958    import G2export_CIF
     1959    #import imp
     1960    #imp.reload(G2export_CIF)   #TODO for debug
     1961    obj = G2export_CIF.ExportProjectCIF(G2frame)
     1962    obj.Exporter(None,seqData=seqData,Controls=Controls)
     1963   
    19521964def ExportSequential(G2frame,data,obj,exporttype):
    19531965    '''
     
    19581970    :param wx.Frame G2frame: the GSAS-II main data tree window
    19591971    :param dict data: the sequential refinement data object
     1972    :param exporter obj: an exporter object
    19601973    :param str exporttype: indicates the type of export ('project' or 'phase')
    19611974    '''
  • trunk/GSASIIdataGUI.py

    r5038 r5042  
    28702870        item = menu.AppendSubMenu(mapmenu,'Maps as','Export density map(s)')
    28712871
    2872         # sequential exports are handled differently; N.B. enabled in testSeqRefineMode
     2872        # sequential exports are handled differently; N.B. en-/disabled in testSeqRefineMode
     2873        item = menu.Append(wx.ID_ANY,'Sequential project as CIF',
     2874                            'Export project from sequential fit as a full CIF')
     2875        self.Bind(wx.EVT_MENU, self.DoSequentialProjExport, item)
     2876        self.ExportSeq.append([menu,item.Id])
    28732877        seqPhasemenu = wx.Menu()
    28742878        item = menu.AppendSubMenu(seqPhasemenu,'Sequential phases','Export phases from sequential fit')
     
    29282932                        data = self.GPXtree.GetItemPyData(Id)
    29292933                        G2IO.ExportSequential(self,data,obj,typ)
    2930                         if '2' in platform.python_version_tuple()[0]:
    2931                             if 'mode' in inspect.getargspec(obj.Writer)[0]:
    2932                                 item = submenu.Append(wx.ID_ANY,obj.formatName,obj.longFormatName)
    2933                                 self.Bind(wx.EVT_MENU, seqMenuItemEventHandler, item)
    2934                         else:
    2935                             if 'mode' in inspect.getfullargspec(obj.Writer)[0]:
    2936                                 item = submenu.Append(wx.ID_ANY,obj.formatName,obj.longFormatName)
    2937                                 self.Bind(wx.EVT_MENU, seqMenuItemEventHandler, item)
    2938                         #                    self.SeqExportLookup[item.GetId()] = (obj,lbl) # lookup table for submenu item
    2939                         # Bind is in UpdateSeqResults
    2940 
     2934                    if '2' in platform.python_version_tuple()[0]:
     2935                        if 'mode' in inspect.getargspec(obj.Writer)[0]:
     2936                            item = submenu.Append(wx.ID_ANY,obj.formatName,obj.longFormatName)
     2937                            self.Bind(wx.EVT_MENU, seqMenuItemEventHandler, item)
     2938                    else:
     2939                        if 'mode' in inspect.getfullargspec(obj.Writer)[0]:
     2940                            item = submenu.Append(wx.ID_ANY,obj.formatName,obj.longFormatName)
     2941                            self.Bind(wx.EVT_MENU, seqMenuItemEventHandler, item)
     2942           
    29412943        item = imagemenu.Append(wx.ID_ANY,'Multiple image controls and masks',
    29422944            'Export image controls and masks for multiple images')
     
    55645566        G2IO.SaveMultipleImg(self)
    55655567
     5568    def DoSequentialProjExport(self,event):
     5569        '''Export a sequential project
     5570
     5571        duplicates part of GSASIIseqGUI.DoSequentialExport
     5572        '''
     5573        Id = GetGPXtreeItemId(self,self.root,'Sequential results')
     5574        if not Id:
     5575            print('Error in DoSequentialProjExport: no Seq Res table. How did this happen?')
     5576            return
     5577        data = self.GPXtree.GetItemPyData(Id)
     5578        Controls = self.GPXtree.GetItemPyData(GetGPXtreeItemId(self,self.root, 'Controls'))
     5579        G2IO.ExportSequentialFullCIF(self,data,Controls)
     5580
    55665581# Data window side of main GUI ################################################
    55675582class G2DataWindow(wx.ScrolledWindow):      #wxscroll.ScrolledPanel):
     
    59025917        self.SequentialEx = wx.Menu(title='')
    59035918        self.SequentialMenu.Append(menu=self.SequentialEx, title='Seq Export')
    5904         for lbl,txt in (('Phase','Export selected phase(s)'),
    5905                         ('Project','Export entire sequential fit'),
    5906                         ('Powder','Export selected powder histogram(s)'),
    5907                         ('sasd','Export selected small angle histogram(s)')
    5908                         ):
     5919        for lbl,txt in (
     5920                ('Project','Export entire sequential fit'),
     5921                ('Phase','Export selected phase(s)'),
     5922                ('Powder','Export selected powder histogram(s)'),
     5923                ('sasd','Export selected small angle histogram(s)')):
    59095924            objlist = []
    59105925            for obj in self.parent.GetTopLevelParent().exporterlist:
     
    59205935                        if 'mode' in inspect.getfullargspec(obj.Writer)[0]:
    59215936                            objlist.append(obj)
    5922             if objlist:
     5937            if objlist or lbl == 'Project':
    59235938                submenu = wx.Menu()
    59245939                item = self.SequentialEx.AppendSubMenu(submenu,lbl+' as',txt)
     5940                if  lbl == 'Project':
     5941                    G2G.Define_wxId('wxID_XPORTSEQFCIF')     
     5942                    submenu.Append(G2G.wxID_XPORTSEQFCIF,'... as full CIF',
     5943                            'Save all sequential refinement results as a CIF file')
    59255944                for obj in objlist:
    59265945                    item = submenu.Append(wx.ID_ANY,obj.formatName,obj.longFormatName)
    59275946                    self.SeqExportLookup[item.GetId()] = (obj,lbl) # lookup table for submenu item
    59285947                    # Bind is in UpdateSeqResults
     5948           
    59295949        G2G.Define_wxId('wxID_XPORTSEQCSV')     
    59305950        self.SequentialEx.Append(G2G.wxID_XPORTSEQCSV,'Save table as CSV',
  • trunk/GSASIIlattice.py

    r5038 r5042  
    24822482        Tindx += SHCoef[term]**2/(2.0*l+1.)
    24832483    return Tindx
    2484    
     2484
     2485UniqueCellByLaue = [
     2486        [['m3','m3m'],(0,)],
     2487        [['3R','3mR'],(0,3)],
     2488        [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
     2489        [['mmm'],(0,1,2)],
     2490        [['2/m'+'a'],(0,1,2,3)],
     2491        [['2/m'+'b'],(0,1,2,4)],
     2492        [['2/m'+'c'],(0,1,2,5)],
     2493        [['-1'],(0,1,2,3,4,5)],
     2494    ]
     2495'''List the unique cell terms by index for each Laue class'''
     2496
     2497cellAlbl = ('a','b','c', 'alpha', 'beta', 'gamma')
     2498'ASCII labels for a, b, c, alpha, beta, gamma'
     2499
     2500cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3')
     2501'unicode labels for a, b, c, alpha, beta, gamma'
     2502 
    24852503# self-test materials follow.
    24862504selftestlist = []
  • trunk/GSASIIphsGUI.py

    r5041 r5042  
    5959import GSASIIIO as G2IO
    6060import GSASIIstrMain as G2stMn
    61 import GSASIIstrIO as G2strIO
     61import GSASIIstrIO as G2stIO
    6262import GSASIImath as G2mth
    6363import GSASIIpwd as G2pwd
     
    65456545                if dlg.ShowModal() == wx.ID_OK:
    65466546                    GPXFile = dlg.GetPath()
    6547                     phaseNames = G2strIO.GetPhaseNames(GPXFile)
     6547                    phaseNames = G2stIO.GetPhaseNames(GPXFile)
    65486548                else:
    65496549                    return
     
    65566556            else:
    65576557                return
    6558             Phase = G2strIO.GetAllPhaseData(GPXFile,PhaseName)
     6558            Phase = G2stIO.GetAllPhaseData(GPXFile,PhaseName)
    65596559            #need cell compatibility check here
    65606560            Layer = {'Name':Phase['General']['Name'],'SameAs':'','Symm':'None'}
     
    70047004            if dlg.ShowModal() == wx.ID_OK:
    70057005                GPXFile = dlg.GetPath()
    7006                 phaseNames = G2strIO.GetPhaseNames(GPXFile)
     7006                phaseNames = G2stIO.GetPhaseNames(GPXFile)
    70077007            else:
    70087008                return
     
    70157015        else:
    70167016            return
    7017         General = G2strIO.GetAllPhaseData(GPXFile,PhaseName)['General']
     7017        General = G2stIO.GetAllPhaseData(GPXFile,PhaseName)['General']
    70187018        data['Layers']['Cell'] = General['Cell']
    70197019        wx.CallAfter(UpdateLayerData)
  • trunk/GSASIIscriptable.py

    r5038 r5042  
    12681268import GSASIIpwd as G2pwd
    12691269import GSASIIstrMain as G2strMain
    1270 import GSASIIstrIO as G2strIO
     1270import GSASIIstrIO as G2stIO
    12711271import GSASIIspc as G2spc
    12721272import GSASIIElem as G2elem
     
    13791379        raise IOError('GPX file {} does not exist'.format(ProjFile))
    13801380    try:
    1381         Project, nameList = G2strIO.GetFullGPX(ProjFile)
     1381        Project, nameList = G2stIO.GetFullGPX(ProjFile)
    13821382    except Exception as msg:
    13831383        raise IOError(msg)
     
    24792479
    24802480            # check that constraints are OK
    2481             errmsg, warnmsg = G2strIO.ReadCheckConstraints(self.filename)
     2481            errmsg, warnmsg = G2stIO.ReadCheckConstraints(self.filename)
    24822482            if errmsg:
    24832483                G2fil.G2Print('Constraint error',errmsg)
     
    25042504
    25052505        # check that constraints are OK
    2506         errmsg, warnmsg = G2strIO.ReadCheckConstraints(self.filename)
     2506        errmsg, warnmsg = G2stIO.ReadCheckConstraints(self.filename)
    25072507        if errmsg:
    25082508            G2fil.G2Print('Constraint error',errmsg)
     
    30063006    def index_ids(self):
    30073007        self.save()
    3008         return G2strIO.GetUsedHistogramsAndPhases(self.filename)
     3008        return G2stIO.GetUsedHistogramsAndPhases(self.filename)
    30093009
    30103010    def get_Constraints(self,ctype):
     
    50195019                                                  parmDict))
    50205020
    5021             A, sigA = G2strIO.cellFill(pfx, sgdata, parmDict, sigDict)
    5022             cellSig = G2strIO.getCellEsd(pfx, sgdata, A, self.proj['Covariance']['data'])
     5021            A, sigA = G2stIO.cellFill(pfx, sgdata, parmDict, sigDict)
     5022            cellSig = G2stIO.getCellEsd(pfx, sgdata, A, self.proj['Covariance']['data'])
    50235023            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
    50245024            cellDict, cellSigDict = {}, {}
  • trunk/GSASIIseqGUI.py

    r5038 r5042  
    588588            for i,val in enumerate(G2lat.A2cell(A)):
    589589                if i in uniqCellIndx[pId]:
    590                     lbl = str(pId)+'::'+cellUlbl[i]
     590                    lbl = str(pId)+'::'+G2lat.cellUlbl[i]
    591591                    parmDict[lbl] = val
    592592            lbl = str(pId)+'::'+'Vol'
     
    641641                for i,val in enumerate(G2lat.A2cell(A)):
    642642                    if i in uniqCellIndx[pId]:
    643                         lbl = str(pId)+'::'+cellUlbl[i]
     643                        lbl = str(pId)+'::'+G2lat.cellUlbl[i]
    644644                        VparmDict[lbl] = val
    645645                lbl = str(pId)+'::'+'Vol'
     
    889889        '''Event handler for all Sequential Export menu items
    890890        '''
     891        if event.GetId() == G2G.wxID_XPORTSEQFCIF:
     892            G2IO.ExportSequentialFullCIF(G2frame,data,Controls)
     893            return
    891894        vals = G2frame.dataWindow.SeqExportLookup.get(event.GetId())
    892895        if vals is None:
     
    10721075        return
    10731076           
    1074 ##### UpdateSeqResults: start processing sequential results here ##########
     1077#---- UpdateSeqResults: start processing sequential results here ##########
    10751078    # lookup table for unique cell parameters by symmetry
    1076     cellGUIlist = [
    1077         [['m3','m3m'],(0,)],
    1078         [['3R','3mR'],(0,3)],
    1079         [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],(0,2)],
    1080         [['mmm'],(0,1,2)],
    1081         [['2/m'+'a'],(0,1,2,3)],
    1082         [['2/m'+'b'],(0,1,2,4)],
    1083         [['2/m'+'c'],(0,1,2,5)],
    1084         [['-1'],(0,1,2,3,4,5)],
    1085         ]
    1086     # cell labels
    1087     cellUlbl = ('a','b','c',u'\u03B1',u'\u03B2',u'\u03B3') # unicode a,b,c,alpha,beta,gamma
    10881079
    10891080    if not data:
     
    11481139        if laue == '2/m':
    11491140            laue += SGdata[pId]['SGUniq']
    1150         for symlist,celllist in cellGUIlist:
     1141        for symlist,celllist in G2lat.UniqueCellByLaue:
    11511142            if laue in symlist:
    11521143                uniqCellIndx[pId] = celllist
     
    11801171    G2frame.Bind(wx.EVT_MENU, DoParEqFit, id=G2G.wxID_DOPARFIT)
    11811172
    1182     for id in G2frame.dataWindow.SeqExportLookup:       
     1173    for id in G2frame.dataWindow.SeqExportLookup:
    11831174        G2frame.Bind(wx.EVT_MENU, DoSequentialExport, id=id)
    11841175    G2frame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=G2G.wxID_XPORTSEQCSV)
     1176    G2frame.Bind(wx.EVT_MENU, DoSequentialExport, id=G2G.wxID_XPORTSEQFCIF)
    11851177
    11861178    EnablePseudoVarMenus()
     
    12321224    #else:
    12331225    #    G2frame.dataWindow.SequentialFile.Enable(G2G.wxID_ORGSEQSEL,False)
    1234     ######  build up the data table by columns -----------------------------------------------
     1226    #-----  build up the data table by columns -----------------------------------------------
    12351227    histNames = foundNames
    12361228    nRows = len(histNames)
     
    12761268            cells = []
    12771269            cellESDs = []
    1278             colLabels += [pfx+cellUlbl[i] for i in uniqCellIndx[pId]]
     1270            colLabels += [pfx+G2lat.cellUlbl[i] for i in uniqCellIndx[pId]]
    12791271            colLabels += [pfx+'Vol']
    12801272            Types += (len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT+':10,5',]
     
    14181410            wtFrList.append(wtFr)
    14191411            if var in data[name]['varyList']:
    1420                 sig = data[name]['sig'][data[name]['varyList'].index(var)]*wtFr/Phases[phase]['Histograms'][name]['Scale'][0]
     1412                sig = data[name]['sig'][data[name]['varyList'].index(var)]*Phases[phase]['General']['Mass']/wtFrSum
     1413            elif var in data[name].get('depParmDict',{}):
     1414                sig = data[name]['depParmDict'][var][1]*Phases[phase]['General']['Mass']/wtFrSum
    14211415            else:
    14221416                sig = 0.0
  • trunk/exports/G2export_CIF.py

    r4955 r5042  
    5858import GSASIIlattice as G2lat
    5959import GSASIIstrMain as G2stMn
    60 import GSASIIstrIO as G2strIO       
     60import GSASIIstrIO as G2stIO       
    6161import GSASIImapvars as G2mv
    6262import GSASIIElem as G2el
     
    7070             'angle_alpha','angle_beta ','angle_gamma',
    7171             'volume']
     72def striphist(var,insChar=''):
     73    'strip a histogram number from a var name'
     74    sv = var.split(':')
     75    if len(sv) <= 1: return var
     76    if sv[1]:
     77        sv[1] = insChar
     78    return ':'.join(sv)
     79
     80def getCellwStrain(phasedict,seqData,pId,histname):
     81    'Get cell parameters and their errors for a sequential fit'
     82    #newCellDict = {}
     83    #if name in seqData and 'newCellDict' in seqData[histname]:
     84    #    newCellDict.update(seqData[histname]['newCellDict'])
     85   
     86    pfx = str(pId)+'::' # prefix for A values from phase
     87    Albls = [pfx+'A'+str(i) for i in range(6)]
     88    Avals = G2lat.cell2A(phasedict['General']['Cell'][1:7])
     89    #AiLookup = {}
     90    DijLookup = {}
     91    zeroDict = dict(zip(Avals,6*[0.,]))
     92    for i,v in enumerate(('D11','D22','D33','D12','D13','D23')):
     93        if pfx+v in seqData[histname]['newCellDict']:
     94            Avals[i] = seqData[histname]['newCellDict'][pfx+v][1]
     95            #AiLookup[seqData[histname]['newCellDict'][pfx+v][0]] = pfx+v
     96            DijLookup[pfx+v] = seqData[histname]['newCellDict'][pfx+v][0]
     97    covData = {  # relabeled with p:h:Dij as p::Ai
     98        'varyList': [DijLookup.get(striphist(v),v) for v in seqData[histname]['varyList']],
     99        'covMatrix': seqData[histname]['covMatrix']}
     100    # apply symmetry
     101    cellDict = dict(zip(Albls,Avals))
     102    try:    # convert to direct cell
     103        A,zeros = G2stIO.cellFill(pfx,phasedict['General']['SGData'],cellDict,zeroDict)
     104        cell = list(G2lat.A2cell(A)) + [G2lat.calc_V(A)]
     105        cE = G2stIO.getCellEsd(pfx,phasedict['General']['SGData'],A,covData)
     106    except:
     107        cell = 7*[None]
     108        cE = 7*[None]
     109    return cell,cE
     110
     111def mkSeqResTable(mode,seqHistList,seqData,Phases,Histograms,Controls):
     112    '''Setup sequential results table (based on code from
     113    GSASIIseqGUI.UpdateSeqResults)
     114
     115    TODO: This should be merged with the table build code in
     116    GSASIIseqGUI.UpdateSeqResults and moved to somewhere non-GUI
     117    like GSASIIstrIO to create a single routine that can be used
     118    in both places, but this means returning some
     119    of the code that has been removed from there
     120    '''
     121
     122    newAtomDict = seqData[seqHistList[0]].get('newAtomDict',{}) # dict with atom positions; relative & absolute
     123    atomLookup = {newAtomDict[item][0]:item for item in newAtomDict if item in seqData['varyList']}
     124    phaseLookup = {Phases[phase]['pId']:phase for phase in Phases}
     125
     126    # make dict of varied cell parameters equivalents
     127    ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined)
     128    Dlookup = {} # provides the Ak term for each Dij term (where terms are refined)
     129    newCellDict = {}
     130    for name in seqHistList:
     131        if name in seqData and 'newCellDict' in seqData[name]:
     132            newCellDict.update(seqData[name]['newCellDict'])
     133    cellAlist = []
     134    for item in newCellDict:
     135        cellAlist.append(newCellDict[item][0])
     136        if item in seqData.get('varyList',[]):
     137            ESDlookup[newCellDict[item][0]] = item
     138            Dlookup[item] = newCellDict[item][0]
     139    # add coordinate equivalents to lookup table
     140    for parm in atomLookup:
     141        Dlookup[atomLookup[parm]] = parm
     142        ESDlookup[parm] = atomLookup[parm]
     143
     144    # get unit cell & symmetry for all phases & initial stuff for later use
     145    RecpCellTerms = {}
     146    SGdata = {}
     147    uniqCellIndx = {}
     148    #initialCell = {}
     149    RcellLbls = {}
     150    zeroDict = {}
     151    for phase in Phases:
     152        pId = Phases[phase]['pId']
     153        pfx = str(pId)+'::' # prefix for A values from phase
     154        RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)]
     155        RecpCellTerms[pId] = G2lat.cell2A(Phases[phase]['General']['Cell'][1:7])
     156        zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,]))
     157        SGdata[pId] = Phases[phase]['General']['SGData']
     158        laue = SGdata[pId]['SGLaue']
     159        if laue == '2/m':
     160            laue += SGdata[pId]['SGUniq']
     161        for symlist,celllist in G2lat.UniqueCellByLaue:
     162            if laue in symlist:
     163                uniqCellIndx[pId] = celllist
     164                break
     165        else: # should not happen
     166            uniqCellIndx[pId] = list(range(6))
     167           
     168    # scan for locations where the variables change
     169    VaryListChanges = [] # histograms where there is a change
     170    combinedVaryList = []
     171    firstValueDict = {}
     172    vallookup = {}
     173    posdict = {}
     174    prevVaryList = []
     175    foundNames = []
     176    missing = 0
     177    for i,name in enumerate(seqHistList):
     178        if name not in seqData:
     179            if missing < 5:
     180                print(" Warning: "+name+" not found")
     181            elif missing == 5:
     182                print (' Warning: more are missing')
     183            missing += 1
     184            continue
     185        foundNames.append(name)
     186        maxPWL = 5
     187        for var,val,sig in zip(seqData[name]['varyList'],seqData[name]['variables'],seqData[name]['sig']):
     188            svar = striphist(var,'*') # wild-carded
     189            if 'PWL' in svar:
     190                if int(svar.split(':')[-1]) > maxPWL:
     191                    continue
     192            if svar not in combinedVaryList:
     193                # add variables to list as they appear
     194                combinedVaryList.append(svar)
     195                firstValueDict[svar] = (val,sig)
     196        if prevVaryList != seqData[name]['varyList']: # this refinement has a different refinement list from previous
     197            prevVaryList = seqData[name]['varyList']
     198            vallookup[name] = dict(zip(seqData[name]['varyList'],seqData[name]['variables']))
     199            posdict[name] = {}
     200            for var in seqData[name]['varyList']:
     201                svar = striphist(var,'*')
     202                if 'PWL' in svar:
     203                    if int(svar.split(':')[-1]) > maxPWL:
     204                        continue
     205                posdict[name][combinedVaryList.index(svar)] = svar
     206            VaryListChanges.append(name)
     207    if missing:
     208        print (' Warning: Total of %d data sets missing from sequential results'%(missing))
     209
     210    #### --- start building table
     211    histNames = foundNames
     212#            sampleParms = GetSampleParms()
     213    nRows = len(histNames)
     214    tblValues = [list(range(nRows))]   # table of values arranged by columns
     215    tblSigs =   [None]                 # a list of sigma values, or None if not defined
     216    tblLabels = ['Number']             # a label for the column
     217    tblTypes = ['int']
     218    # start with Rwp values
     219    tblValues += [[seqData[name]['Rvals']['Rwp'] for name in histNames]]
     220    tblSigs += [None]
     221    tblLabels += ['Rwp']
     222    tblTypes += ['10,3']
     223    # add changing sample parameters to table
     224    sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[],
     225                 'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[],
     226                 'Chi':[],'Phi':[],'Azimuth':[],}
     227    for key in sampleParmDict:
     228        for h in histNames:
     229            var = ":" + str(Histograms[h]['hId']) + ":" + key
     230            sampleParmDict[key].append(seqData[h]['parmDict'].get(var))
     231        if not np.all(np.array(sampleParmDict[key]) == sampleParmDict[key][0]):
     232            tblValues += [sampleParmDict[key]]
     233            tblSigs.append(None)
     234            if 'FreePrm' in key and key in Controls:
     235                tblLabels.append(Controls[item])
     236            else:
     237                tblLabels.append(key)
     238            tblTypes += ['float']
     239
     240    # add unique cell parameters 
     241    if len(newCellDict):
     242        for pId in sorted(RecpCellTerms):
     243            pfx = str(pId)+'::' # prefix for A values from phase
     244            cells = []
     245            cellESDs = []
     246            Albls = [pfx+'A'+str(i) for i in range(6)]
     247            for name in histNames:
     248                #if name not in Histograms: continue
     249                hId = Histograms[name]['hId']
     250                phfx = '%d:%d:'%(pId,hId)
     251                esdLookUp = {}
     252                dLookup = {}
     253                for item in seqData[name]['newCellDict']:
     254                    if phfx+item.split('::')[1] in seqData[name]['varyList']:
     255                        esdLookUp[newCellDict[item][0]] = item
     256                        dLookup[item] = newCellDict[item][0]
     257                covData = {'varyList': [dLookup.get(striphist(v),v) for v in seqData[name]['varyList']],
     258                    'covMatrix': seqData[name]['covMatrix']}
     259                A = RecpCellTerms[pId][:] # make copy of starting A values
     260                # update with refined values
     261                for i,j in enumerate(('D11','D22','D33','D12','D13','D23')):
     262                    var = str(pId)+'::A'+str(i)
     263                    Dvar = str(pId)+':'+str(hId)+':'+j
     264                    # apply Dij value if non-zero
     265                    if Dvar in seqData[name]['parmDict']:
     266                        parmDict = seqData[name]['parmDict']
     267                        if parmDict[Dvar] != 0.0:
     268                            A[i] += parmDict[Dvar]
     269                    # override with fit result if is Dij varied
     270                    if var in cellAlist:
     271                        try:
     272                            A[i] = seqData[name]['newCellDict'][esdLookUp[var]][1] # get refined value
     273                        except KeyError:
     274                            pass
     275                # apply symmetry
     276                cellDict = dict(zip(Albls,A))
     277                try:    # convert to direct cell
     278                    A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId])
     279                    c = G2lat.A2cell(A)
     280                    vol = G2lat.calc_V(A)
     281                    cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData)
     282                except:
     283                    c = 6*[None]
     284                    cE = 6*[None]
     285                    vol = None
     286                # add only unique values to table
     287                if name in Phases[phaseLookup[pId]]['Histograms']:
     288                    cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]]
     289                    cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]]
     290                else:
     291                    cells += [[None for i in uniqCellIndx[pId]]+[None]]
     292                    cellESDs += [[None for i in uniqCellIndx[pId]]+[None]]
     293            p = phaseLookup[pId]
     294            tblLabels += ['{}, {}'.format(G2lat.cellAlbl[i],p) for i in uniqCellIndx[pId]]
     295            tblTypes += ['10,5' if i <3 else '10,3' for i in uniqCellIndx[pId]]
     296            tblLabels.append('{}, {}'.format('Volume',p))
     297            tblTypes += ['10,3']
     298            tblValues += zip(*cells)
     299            tblSigs += zip(*cellESDs)
     300
     301    # sort out the variables in their selected order
     302    varcols = 0
     303    varlbls = []
     304    for d in posdict.values():
     305        varcols = max(varcols,max(d.keys())+1)
     306    # get labels for each column
     307    for i in range(varcols):
     308        lbl = ''
     309        for h in VaryListChanges:
     310            if posdict[h].get(i):
     311                if posdict[h].get(i) in lbl: continue
     312                if lbl != "": lbl += '/'
     313                lbl += posdict[h].get(i)
     314        varlbls.append(lbl)
     315    vals = []
     316    esds = []
     317    varsellist = None        # will be a list of variable names in the order they are selected to appear
     318    # tabulate values for each hist, leaving None for blank columns
     319    for name in histNames:
     320        if name in posdict:
     321            varsellist = [posdict[name].get(i) for i in range(varcols)]
     322            # translate variable names to how they will be used in the headings
     323            vs = [striphist(v,'*') for v in seqData[name]['varyList']]
     324            # determine the index for each column (or None) in the seqData[]['variables'] and ['sig'] lists
     325            sellist = [vs.index(v) if v is not None else None for v in varsellist]
     326            #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(seqData[name]['varyList'])]
     327        if not varsellist: raise Exception()
     328        vals.append([seqData[name]['variables'][s] if s is not None else None for s in sellist])
     329        esds.append([seqData[name]['sig'][s] if s is not None else None for s in sellist])
     330    tblValues += zip(*vals)
     331    tblSigs += zip(*esds)
     332    tblLabels += varlbls
     333    tblTypes += ['float' for i in varlbls]
     334   
     335    # tabulate constrained variables, removing histogram numbers if needed
     336    # from parameter label
     337    depValDict = {}
     338    depSigDict = {}
     339    for name in histNames:
     340        for var in seqData[name].get('depParmDict',{}):
     341            val,sig = seqData[name]['depParmDict'][var]
     342            svar = striphist(var,'*')
     343            if svar not in depValDict:
     344               depValDict[svar] = [val]
     345               depSigDict[svar] = [sig]
     346            else:
     347               depValDict[svar].append(val)
     348               depSigDict[svar].append(sig)
     349
     350    # add the dependent constrained variables to the table
     351    for var in sorted(depValDict):
     352        if len(depValDict[var]) != len(histNames): continue
     353        tblLabels.append(var)
     354        tblTypes.append('10,5')
     355        tblSigs += [depSigDict[var]]
     356        tblValues += [depValDict[var]]
     357
     358    # add refined atom parameters to table
     359    for parm in sorted(atomLookup):
     360        tblLabels.append(parm)
     361        tblTypes.append('10,5')
     362        tblValues += [[seqData[name]['newAtomDict'][atomLookup[parm]][1] for name in histNames]]
     363        if atomLookup[parm] in seqData[histNames[0]]['varyList']:
     364            col = seqData[histNames[0]]['varyList'].index(atomLookup[parm])
     365            tblSigs += [[seqData[name]['sig'][col] for name in histNames]]
     366        else:
     367            tblSigs += [None]
     368
     369    # compute and add weight fractions to table if varied
     370    for phase in Phases:
     371        var = str(Phases[phase]['pId'])+':*:Scale'
     372        if var not in combinedVaryList+list(depValDict.keys()): continue
     373        wtFrList = []
     374        sigwtFrList = []
     375        for i,name in enumerate(histNames):
     376            if name not in Phases[phase]['Histograms']:
     377                wtFrList.append(None)
     378                sigwtFrList.append(0.0)
     379                continue
     380            elif not Phases[phase]['Histograms'][name]['Use']:
     381                wtFrList.append(None)
     382                sigwtFrList.append(0.0)
     383                continue
     384            wtFrSum = 0.
     385            for phase1 in Phases:
     386                if name not in Phases[phase1]['Histograms']: continue
     387                if not Phases[phase1]['Histograms'][name]['Use']: continue
     388                wtFrSum += Phases[phase1]['Histograms'][name]['Scale'][0]*Phases[phase1]['General']['Mass']
     389            var = str(Phases[phase]['pId'])+':'+str(i)+':Scale'
     390            wtFr = Phases[phase]['Histograms'][name]['Scale'][0]*Phases[phase]['General']['Mass']/wtFrSum
     391            wtFrList.append(wtFr)
     392            if var in seqData[name]['varyList']:
     393                sig = seqData[name]['sig'][seqData[name]['varyList'].index(var)]*wtFr/Phases[phase]['Histograms'][name]['Scale'][0]
     394            elif var in seqData[name].get('depParmDict',{}):
     395                _,sig = seqData[name]['depParmDict'][var]
     396            else:
     397                sig = 0.0
     398            sigwtFrList.append(sig)
     399        p = phaseLookup[Phases[phase]['pId']]
     400        tblLabels.append(p + ' Wgt Frac')
     401        tblTypes.append('10,4')
     402        tblValues += [wtFrList]
     403        tblSigs += [sigwtFrList]
     404    return tblLabels,tblValues,tblSigs,tblTypes
    72405
    73406
     
    220553  Site symmetry @ origin: {}, multiplicity: {}
    221554'''.format(RBObj['RBname'],len(RBModel['rbTypes']),Sytsym,Mult)
    222         for i in G2strIO.WriteResRBModel(RBModel):
     555        for i in G2stIO.WriteResRBModel(RBModel):
    223556            s += i
    224557        s += '\n Location:\n'
    225         for i in G2strIO.WriteRBObjPOAndSig(pfx,'RBR',rbsx,parmDict,sigDict):
     558        for i in G2stIO.WriteRBObjPOAndSig(pfx,'RBR',rbsx,parmDict,sigDict):
    226559            s += i+'\n'
    227         for i in G2strIO.WriteRBObjTLSAndSig(pfx,'RBR',rbsx,
     560        for i in G2stIO.WriteRBObjTLSAndSig(pfx,'RBR',rbsx,
    228561                        RBObj['ThermalMotion'][0],parmDict,sigDict):
    229562            s += i
    230563        nTors = len(RBObj['Torsions'])
    231564        if nTors:
    232             for i in G2strIO.WriteRBObjTorAndSig(pfx,rbsx,parmDict,sigDict,
     565            for i in G2stIO.WriteRBObjTorAndSig(pfx,rbsx,parmDict,sigDict,
    233566                        nTors):
    234567                s += i
     
    255588  Site symmetry @ origin: {}, multiplicity: {}
    256589'''.format(RBObj['RBname'],len(RBModel['rbTypes']),Sytsym,Mult)
    257         for i in G2strIO.WriteVecRBModel(RBModel,sigDict,irb):
     590        for i in G2stIO.WriteVecRBModel(RBModel,sigDict,irb):
    258591            s += i
    259592        s += '\n Location:\n'
    260         for i in G2strIO.WriteRBObjPOAndSig(pfx,'RBV',rbsx,parmDict,sigDict):
     593        for i in G2stIO.WriteRBObjPOAndSig(pfx,'RBV',rbsx,parmDict,sigDict):
    261594            s += i+'\n'
    262         for i in G2strIO.WriteRBObjTLSAndSig(pfx,'RBV',rbsx,
     595        for i in G2stIO.WriteRBObjTLSAndSig(pfx,'RBV',rbsx,
    263596                        RBObj['ThermalMotion'][0],parmDict,sigDict):
    264597            s += i
     
    399732
    400733# Refactored over here to allow access by GSASIIscriptable.py
     734def WriteSeqAtomsNuclear(fp, cell, phasedict, phasenam, hist, seqData, RBparms):
     735    'Write atom positions to CIF'
     736    General = phasedict['General']
     737    cx,ct,cs,cia = General['AtomPtrs']
     738    GS = G2lat.cell2GS(cell[:6])
     739    Amat = G2lat.cell2AB(cell[:6])[0]
     740
     741    # phasedict = self.Phases[phasenam] # pointer to current phase info
     742    parmDict = seqData[hist]['parmDict']
     743    sigDict = dict(zip(seqData[hist]['varyList'],seqData[hist]['sig']))
     744    Atoms = phasedict['Atoms']
     745    cfrac = cx+3
     746    fpfx = str(phasedict['pId'])+'::Afrac:'
     747    for i,at in enumerate(Atoms):
     748        fval = parmDict.get(fpfx+str(i),at[cfrac])
     749        if fval != 0.0:
     750            break
     751    else:
     752        WriteCIFitem(fp, '\n# PHASE HAS NO ATOMS!')
     753        return
     754
     755    WriteCIFitem(fp, '\n# ATOMIC COORDINATES AND DISPLACEMENT PARAMETERS')
     756    WriteCIFitem(fp, 'loop_ '+
     757                 '\n   _atom_site_label'+
     758                 '\n   _atom_site_type_symbol'+
     759                 '\n   _atom_site_fract_x'+
     760                 '\n   _atom_site_fract_y'+
     761                 '\n   _atom_site_fract_z'+
     762                 '\n   _atom_site_occupancy'+
     763                 '\n   _atom_site_adp_type'+
     764                 '\n   _atom_site_U_iso_or_equiv'+
     765                 '\n   _atom_site_site_symmetry_multiplicity')
     766
     767    varnames = {cx:'Ax',cx+1:'Ay',cx+2:'Az',cx+3:'Afrac',
     768                cia+1:'AUiso',cia+2:'AU11',cia+3:'AU22',cia+4:'AU33',
     769                cia+5:'AU12',cia+6:'AU13',cia+7:'AU23'}
     770
     771    labellist = []  # used to make atom labels unique as required in CIF
     772    pfx = str(phasedict['pId'])+'::'
     773    # loop over all atoms
     774    naniso = 0
     775
     776    for i,at in enumerate(Atoms):
     777        if phasedict['General']['Type'] == 'macromolecular':
     778            label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
     779            s = PutInCol(MakeUniqueLabel(label,labellist),15) # label
     780        else:
     781            s = PutInCol(MakeUniqueLabel(at[ct-1],labellist),6) # label
     782        fval = parmDict.get(fpfx+str(i),at[cfrac])
     783        if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact)
     784        s += PutInCol(FmtAtomType(at[ct]),4) # type
     785        if at[cia] == 'I':
     786            adp = 'Uiso '
     787        else:
     788            adp = 'Uani '
     789            naniso += 1
     790            t = G2lat.Uij2Ueqv(at[cia+2:cia+8],GS,Amat)[0]
     791            for j in (2,3,4):
     792                var = pfx+varnames[cia+j]+":"+str(i)
     793        for j in (cx,cx+1,cx+2,cx+3,cia,cia+1):
     794            if j in (cx,cx+1,cx+2):
     795                dig = 11
     796                sigdig = -0.00009
     797            else:
     798                dig = 10
     799                sigdig = -0.0009
     800            if j == cia:
     801                s += adp
     802            else:
     803                var = pfx+varnames[j]+":"+str(i)
     804                dvar = pfx+"d"+varnames[j]+":"+str(i)
     805                if dvar not in sigDict:
     806                    dvar = var
     807                if j == cia+1 and adp == 'Uani ':
     808                    sig = sigdig
     809                    val = t
     810                else:
     811                    #print var,(var in parmDict),(var in sigDict)
     812                    val = parmDict.get(var,at[j])
     813                    sig = sigDict.get(dvar,sigdig)
     814                    if dvar in G2mv.GetDependentVars(): # do not include an esd for dependent vars
     815                        sig = -abs(sig)
     816                s += PutInCol(G2mth.ValEsd(val,sig),dig)
     817        s += PutInCol(at[cs+1],3)
     818        WriteCIFitem(fp, s)
     819    if naniso != 0:
     820        # now loop over aniso atoms
     821        WriteCIFitem(fp, '\nloop_' + '\n   _atom_site_aniso_label' +
     822                     '\n   _atom_site_aniso_U_11' + '\n   _atom_site_aniso_U_22' +
     823                     '\n   _atom_site_aniso_U_33' + '\n   _atom_site_aniso_U_12' +
     824                     '\n   _atom_site_aniso_U_13' + '\n   _atom_site_aniso_U_23')
     825        for i,at in enumerate(Atoms):
     826            fval = parmDict.get(fpfx+str(i),at[cfrac])
     827            if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact)
     828            if at[cia] == 'I': continue
     829            s = PutInCol(labellist[i],6) # label
     830            for j in (2,3,4,5,6,7):
     831                sigdig = -0.0009
     832                var = pfx+varnames[cia+j]+":"+str(i)
     833                val = parmDict.get(var,at[cia+j])
     834                sig = sigDict.get(var,sigdig)
     835                s += PutInCol(G2mth.ValEsd(val,sig),11)
     836            WriteCIFitem(fp, s)
     837    # save information about rigid bodies
     838    header = False
     839    num = 0
     840    rbAtoms = []
     841    for irb,RBObj in enumerate(phasedict['RBModels'].get('Residue',[])):
     842        if not header:
     843            header = True
     844            RBheader(fp)
     845        jrb = RBparms['RBIds']['Residue'].index(RBObj['RBId'])
     846        rbsx = str(irb)+':'+str(jrb)
     847        num += 1
     848        WriteCIFitem(fp,'',str(num))
     849        RBModel = RBparms['Residue'][RBObj['RBId']]
     850        SGData = phasedict['General']['SGData']
     851        Sytsym,Mult = G2spc.SytSym(RBObj['Orig'][0],SGData)[:2]
     852        s = '''GSAS-II residue rigid body "{}" with {} atoms
     853  Site symmetry @ origin: {}, multiplicity: {}
     854'''.format(RBObj['RBname'],len(RBModel['rbTypes']),Sytsym,Mult)
     855        for i in G2stIO.WriteResRBModel(RBModel):
     856            s += i
     857        s += '\n Location:\n'
     858        for i in G2stIO.WriteRBObjPOAndSig(pfx,'RBR',rbsx,parmDict,sigDict):
     859            s += i+'\n'
     860        for i in G2stIO.WriteRBObjTLSAndSig(pfx,'RBR',rbsx,
     861                        RBObj['ThermalMotion'][0],parmDict,sigDict):
     862            s += i
     863        nTors = len(RBObj['Torsions'])
     864        if nTors:
     865            for i in G2stIO.WriteRBObjTorAndSig(pfx,rbsx,parmDict,sigDict,
     866                        nTors):
     867                s += i
     868        WriteCIFitem(fp,'',s.rstrip())
     869       
     870        pId = phasedict['pId']
     871        for i in RBObj['Ids']:
     872            lbl = G2obj.LookupAtomLabel(pId,G2obj.LookupAtomId(pId,i))[0]
     873            rbAtoms.append('{:7s} 1_555 {:3d} ?'.format(lbl,num))
     874        #GSASIIpath.IPyBreak()
     875
     876    for irb,RBObj in enumerate(phasedict['RBModels'].get('Vector',[])):
     877        if not header:
     878            header = True
     879            RBheader(fp)
     880        jrb = RBparms['RBIds']['Vector'].index(RBObj['RBId'])
     881        rbsx = str(irb)+':'+str(jrb)
     882        num += 1
     883        WriteCIFitem(fp,'',str(num))
     884        RBModel = RBparms['Vector'][RBObj['RBId']]
     885        SGData = phasedict['General']['SGData']
     886        Sytsym,Mult = G2spc.SytSym(RBObj['Orig'][0],SGData)[:2]
     887        s = '''GSAS-II vector rigid body "{}" with {} atoms
     888  Site symmetry @ origin: {}, multiplicity: {}
     889'''.format(RBObj['RBname'],len(RBModel['rbTypes']),Sytsym,Mult)
     890        for i in G2stIO.WriteVecRBModel(RBModel,sigDict,irb):
     891            s += i
     892        s += '\n Location:\n'
     893        for i in G2stIO.WriteRBObjPOAndSig(pfx,'RBV',rbsx,parmDict,sigDict):
     894            s += i+'\n'
     895        for i in G2stIO.WriteRBObjTLSAndSig(pfx,'RBV',rbsx,
     896                        RBObj['ThermalMotion'][0],parmDict,sigDict):
     897            s += i
     898        WriteCIFitem(fp,'',s.rstrip())
     899       
     900        pId = phasedict['pId']
     901        for i in RBObj['Ids']:
     902            lbl = G2obj.LookupAtomLabel(pId,G2obj.LookupAtomId(pId,i))[0]
     903            rbAtoms.append('{:7s} 1_555 {:3d} ?'.format(lbl,num))
     904
     905    if rbAtoms:
     906        WriteCIFitem(fp,'loop_\n    _restr_rigid_body.id'+
     907            '\n    _restr_rigid_body.atom_site_label\n    _restr_rigid_body.site_symmetry'+
     908            '\n    _restr_rigid_body.class_id\n    _restr_rigid_body.details')
     909        for i,l in enumerate(rbAtoms):
     910            WriteCIFitem(fp,'   {:5d} {}'.format(i+1,l))
     911           
     912# Refactored over here to allow access by GSASIIscriptable.py
    401913def MakeUniqueLabel(lbl, labellist):
    402914    lbl = lbl.strip()
     
    481993    massDict = dict(zip(General['AtomTypes'],General['AtomMass']))
    482994    cellmass = 0
     995    elmLookup = {}
    483996    for i,at in enumerate(Atoms):
    484997        atype = at[ct].strip()
     
    4961009        cellmass += massDict[at[ct]]*mult*fval
    4971010        compDict[atype] = compDict.get(atype,0.0) + mult*fval
     1011        elmLookup[atype] = at[ct].strip()
    4981012        if fval == 1: sitemultlist.append(mult)
    4991013    if len(compDict.keys()) == 0: return # no elements!
     
    5381052    for elem in HillSortElements(list(compDict.keys())):
    5391053        s = '  '
    540         s += PutInCol(elem,4)
     1054        elmsym = elmLookup[elem]
     1055        # CIF does not allow underscore in element symbol (https://www.iucr.org/__data/iucr/cifdic_html/1/cif_core.dic/Iatom_type_symbol.html)
     1056        if elmsym.endswith("_"):
     1057             s += PutInCol(elmsym.replace('_',''))
     1058        elif '_' in elmsym:
     1059             s += PutInCol(elmsym.replace('_','~'))
     1060        else:
     1061            s += PutInCol(elmsym,7)
    5411062        s += PutInCol(G2mth.ValEsd(compDict[elem],-0.009,True),5)
    5421063        if not quickmode:
     
    5441065                if i != 'fc':
    5451066                    for j in range(4):
    546                         if elem in FFtable:
    547                             val = G2mth.ValEsd(FFtable[elem][i][j],-0.0009,True)
     1067                        if elmsym in FFtable:
     1068                            val = G2mth.ValEsd(FFtable[elmsym][i][j],-0.0009,True)
    5481069                        else:
    5491070                            val = '?'
     
    5511072                        s += PutInCol(val,9)
    5521073                else:
    553                     if elem in FFtable:
    554                         val = G2mth.ValEsd(FFtable[elem][i],-0.0009,True)
     1074                    if elmsym in FFtable:
     1075                        val = G2mth.ValEsd(FFtable[elmsym][i],-0.0009,True)
    5551076                    else:
    5561077                        val = '?'
    5571078                    s += ' '
    5581079                    s += PutInCol(val,9)
    559             if elem in BLtable:
    560                 bldata = BLtable[elem]
     1080            if elmsym in BLtable:
     1081                bldata = BLtable[elmsym]
    5611082                #isotope = bldata[0]
    5621083                #mass = bldata[1]['Mass']
     
    7391260            pId = phasedict['pId']
    7401261            hId = self.Histograms[h]['hId']
    741             cellList,cellSig = G2strIO.getCellSU(pId,hId,
     1262            cellList,cellSig = G2stIO.getCellSU(pId,hId,
    7421263                                        phasedict['General']['SGData'],
    7431264                                        self.parmDict,
     
    7511272            pId = phasedict['pId']
    7521273            hId = self.Histograms[h]['hId']
    753             cellList,cellSig = G2strIO.getCellSU(pId,hId,
     1274            cellList,cellSig = G2stIO.getCellSU(pId,hId,
    7541275                                        phasedict['General']['SGData'],
    7551276                                        self.parmDict,
     
    7611282            WriteCIFitem(self.fp, line)       
    7621283
    763     def _Exporter(self,event=None,phaseOnly=None,histOnly=None,IncludeOnlyHist=None):
     1284    def _Exporter(self,event=None,phaseOnly=None,histOnly=None):
    7641285        '''Basic code to export a CIF. Export can be full or simple, as set by
    7651286        phaseOnly and histOnly which skips distances & angles, etc.
     
    7671288        :param bool phaseOnly: used to export only one phase
    7681289        :param bool histOnly: used to export only one histogram
    769         :param bool IncludeOnlyHist: used for a full CIF that includes only one of the
    770             histograms (from a sequential fit) #TODO: needs lots of work!
    7711290        '''
    7721291
     
    7821301                         self.CIFdate+'  Initial software-generated CIF')
    7831302
    784         def WriteOverall():
     1303        def WriteOverall(mode=None):
    7851304            '''Write out overall refinement information.
    7861305
     
    8031322                except KeyError:
    8041323                    pass
     1324            WriteCIFitem(self.fp, '_refine_ls_matrix_type','full')
     1325
     1326            if mode == 'seq': return
    8051327            try:
    8061328                vars = str(len(self.OverallParms['Covariance']['varyList']))
     
    8371359                # _refine_ls_R_factor_all
    8381360                # _refine_ls_R_factor_obs
    839             WriteCIFitem(self.fp, '_refine_ls_matrix_type','full')
    8401361            #WriteCIFitem(self.fp, '_refine_ls_matrix_type','userblocks')
    8411362
     
    10201541            return s
    10211542
    1022         def FormatPhaseProfile(phasenam):
     1543        def FormatPhaseProfile(phasenam,hist=''):
    10231544            '''Format the phase-related profile parameters (size/strain)
    10241545            with a string description.
     
    10281549            s = ''
    10291550            phasedict = self.Phases[phasenam] # pointer to current phase info
     1551            if hist:
     1552                parmDict = self.seqData[hist]['parmDict']
     1553                sigDict = dict(zip(self.seqData[hist]['varyList'],self.seqData[hist]['sig']))
     1554            else:
     1555                parmDict = self.parmDict
     1556                sigDict = self.sigDict
     1557           
    10301558            SGData = phasedict['General'] ['SGData']
    10311559            for histogram in sorted(phasedict['Histograms']):
     1560                if hist is not None and hist != histogram: continue
    10321561                if histogram.startswith("HKLF"): continue # powder only
    10331562                Histogram = self.Histograms.get(histogram)
     
    10521581                    for i,item in enumerate(names):
    10531582                        name = phfx+item
    1054                         sig = self.sigDict.get(name,-0.009)
    1055                         s += G2mth.ValEsd(size[1][i],sig)+', '
     1583                        val = parmDict.get(name,size[1][i])
     1584                        sig = sigDict.get(name,-0.009)
     1585                        s += G2mth.ValEsd(val,sig)+', '
    10561586                elif 'ellip' in size[0]:
    10571587                    s += 'parameters: S11, S22, S33, S12, S13, S23, G/L mix\n    '
    10581588                    for i in range(6):
    10591589                        name = phfx+'Size:'+str(i)
    1060                         sig = self.sigDict.get(name,-0.009)
    1061                         s += G2mth.ValEsd(size[4][i],sig)+', '
    1062                     sig = self.sigDict.get(phfx+'Size;mx',-0.009)
     1590                        val = parmDict.get(name,size[4][i])
     1591                        sig = sigDict.get(name,-0.009)
     1592                        s += G2mth.ValEsd(val,sig)+', '
     1593                    sig = sigDict.get(phfx+'Size;mx',-0.009)
    10631594                    s += G2mth.ValEsd(size[1][2],sig)+', '
    10641595                else:       #isotropic
     
    10671598                    for item in names:
    10681599                        name = phfx+item
    1069                         sig = self.sigDict.get(name,-0.009)
    1070                         s += G2mth.ValEsd(size[1][i],sig)+', '
     1600                        val = parmDict.get(name,size[1][i])
     1601                        sig = sigDict.get(name,-0.009)
     1602                        s += G2mth.ValEsd(val,sig)+', '
    10711603                        i = 2    #skip the aniso value
    10721604                s += '\n  Microstrain, "%s" model (10^6^ * delta Q/Q)\n  '%(mustrain[0])
     
    10781610                    for i,item in enumerate(names):
    10791611                        name = phfx+item
    1080                         sig = self.sigDict.get(name,-0.009)
    1081                         s += G2mth.ValEsd(mustrain[1][i],sig)+', '
     1612                        val = parmDict.get(name,mustrain[1][i])
     1613                        sig = sigDict.get(name,-0.009)
     1614                        s += G2mth.ValEsd(val,sig)+', '
    10821615                elif 'general' in mustrain[0]:
    10831616                    names = 'parameters: '
     
    10911624                    for i in range(len(mustrain[4])):
    10921625                        name = phfx+'Mustrain:'+str(i)
    1093                         sig = self.sigDict.get(name,-0.009)
     1626                        val = parmDict.get(name,mustrain[4][i])
     1627                        sig = sigDict.get(name,-0.009)
    10941628                        if len(txt) > 60:
    10951629                            s += txt+'\n    '
    10961630                            txt = ''
    1097                         txt += G2mth.ValEsd(mustrain[4][i],sig)+', '
     1631                        txt += G2mth.ValEsd(val,sig)+', '
    10981632                    s += txt
    1099                     sig = self.sigDict.get(phfx+'Mustrain;mx',-0.009)
    1100                     s += G2mth.ValEsd(mustrain[1][2],sig)+', '
     1633                    name = phfx+'Mustrain;mx'
     1634                    val = parmDict.get(name,mustrain[1][2])
     1635                    sig = sigDict.get(name,-0.009)
     1636                    s += G2mth.ValEsd(val,sig)+', '
    11011637
    11021638                else:       #isotropic
     
    11051641                    for item in names:
    11061642                        name = phfx+item
    1107                         sig = self.sigDict.get(name,-0.009)
    1108                         s += G2mth.ValEsd(mustrain[1][i],sig)+', '
     1643                        val = parmDict.get(name,mustrain[1][i])
     1644                        sig = sigDict.get(name,-0.009)
     1645                        s += G2mth.ValEsd(val,sig)+', '
    11091646                        i = 2    #skip the aniso value
    11101647                s1 = '  \n  Macrostrain parameters: '
     
    11161653                for i in range(len(names)):
    11171654                    name = phfx+names[i]
    1118                     sig = self.sigDict.get(name,-0.000009)
    1119                     s1 += G2mth.ValEsd(hstrain[0][i],sig)+', '
     1655                    val = parmDict.get(name,hstrain[0][i])
     1656                    sig = sigDict.get(name,-0.000009)
     1657                    s1 += G2mth.ValEsd(val,sig)+', '
    11201658                    if hstrain[0][i]: macrostrain = True
    11211659                if macrostrain:
     
    11491687                labellist.append(lbl)
    11501688
    1151         def WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList):
     1689        def WriteDistances(phasenam):
    11521690            '''Report bond distances and angles for the CIF
    11531691
     
    12941832                    WriteCIFitem(self.fp, line)
    12951833
     1834
     1835        def WriteSeqDistances(phasenam,histname,phasedict,cellList,seqData):
     1836            '''Report bond distances and angles for the CIF from a Sequential fit
     1837
     1838            Note that _geom_*_symmetry_* fields are values of form
     1839            n_klm where n is the symmetry operation in SymOpList (counted
     1840            starting with 1) and (k-5, l-5, m-5) are translations to add
     1841            to (x,y,z). See
     1842            http://www.iucr.org/__data/iucr/cifdic_html/1/cif_core.dic/Igeom_angle_site_symmetry_.html
     1843
     1844            TODO: this is based on WriteDistances and could likely be merged with that
     1845            without too much work.
     1846
     1847            TODO: need a method to select publication flags for distances/angles
     1848            '''
     1849            #breakpoint()
     1850            Atoms = phasedict['Atoms']
     1851            generalData = phasedict['General']
     1852            parmDict = seqData[histname]['parmDict']
     1853#            sigDict = dict(zip(seqData[hist]['varyList'],seqData[hist]['sig']))
     1854            # create a dict for storing Pub flag for bonds/angles, if needed
     1855            if phasedict['General'].get("DisAglHideFlag") is None:
     1856                phasedict['General']["DisAglHideFlag"] = {}
     1857            DisAngSel = phasedict['General']["DisAglHideFlag"]
     1858            cx,ct,cs,cia = phasedict['General']['AtomPtrs']
     1859            cn = ct-1
     1860#            fpfx = str(phasedict['pId'])+'::Afrac:'
     1861            cfrac = cx+3
     1862            DisAglData = {}
     1863            # create a list of atoms, but skip atoms with zero occupancy
     1864            xyz = []
     1865            fpfx = str(phasedict['pId'])+'::Afrac:'
     1866            for i,atom in enumerate(Atoms):
     1867                if parmDict.get(fpfx+str(i),atom[cfrac]) == 0.0: continue
     1868                thisatom = [i] + atom[cn:cn+2]
     1869                for j,lab in enumerate(['x','y','z']):
     1870                    xyzkey = str(phasedict['pId'])+'::A'+ lab + ':' +str(i)
     1871                    thisatom.append(parmDict.get(xyzkey,atom[cx+j]))
     1872                xyz.append(thisatom)
     1873            DisAglData['OrigAtoms'] = xyz
     1874            DisAglData['TargAtoms'] = xyz
     1875            SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps(
     1876                generalData['SGData'])
     1877
     1878#            xpandSGdata = generalData['SGData'].copy()
     1879#            xpandSGdata.update({'SGOps':symOpList,
     1880#                                'SGInv':False,
     1881#                                'SGLatt':'P',
     1882#                                'SGCen':np.array([[0, 0, 0]]),})
     1883#            DisAglData['SGData'] = xpandSGdata
     1884            DisAglData['SGData'] = generalData['SGData'].copy()
     1885
     1886            DisAglData['Cell'] = cellList  #+ volume
     1887            if 'pId' in phasedict:
     1888                DisAglData['pId'] = phasedict['pId']
     1889                DisAglData['covData'] = seqData[histname]
     1890                # self.OverallParms['Covariance']
     1891            try:
     1892                AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle(
     1893                    generalData['DisAglCtls'],
     1894                    DisAglData)
     1895            except KeyError:        # inside DistAngle for missing atom types in DisAglCtls
     1896                print(u'**** ERROR computing distances & angles for phase {} ****\nresetting to default values'.format(phasenam))
     1897                data = generalData['DisAglCtls'] = {}
     1898                data['Name'] = generalData['Name']
     1899                data['Factors'] = [0.85,0.85]
     1900                data['AtomTypes'] = generalData['AtomTypes']
     1901                data['BondRadii'] = generalData['BondRadii'][:]
     1902                data['AngleRadii'] = generalData['AngleRadii'][:]
     1903                try:
     1904                    AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle(
     1905                        generalData['DisAglCtls'],
     1906                        DisAglData)
     1907                except:
     1908                    print('Reset failed. To fix this, use the Reset button in the "edit distance/angle menu" for this phase')
     1909                    return
     1910
     1911            # loop over interatomic distances for this phase
     1912            WriteCIFitem(self.fp, '\n# MOLECULAR GEOMETRY')
     1913            First = True
     1914            for i in sorted(AtomLabels.keys()):
     1915                Dist = DistArray[i]
     1916                for D in Dist:
     1917                    line = '  '+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[D[0]],6)
     1918                    sig = D[4]
     1919                    if sig == 0: sig = -0.00009
     1920                    line += PutInCol(G2mth.ValEsd(D[3],sig,True),10)
     1921                    line += "  1_555 "
     1922                    symopNum = G2opcodes.index(D[2])
     1923                    line += " {:3d}_".format(symopNum+1)
     1924                    for d,o in zip(D[1],offsetList[symopNum]):
     1925                        line += "{:1d}".format(d-o+5)
     1926                    if DisAngSel.get((i,tuple(D[0:3]))):
     1927                        line += " no"
     1928                    else:
     1929                        line += " yes"
     1930                    if First:
     1931                        First = False
     1932                        WriteCIFitem(self.fp, 'loop_' +
     1933                         '\n   _geom_bond_atom_site_label_1' +
     1934                         '\n   _geom_bond_atom_site_label_2' +
     1935                         '\n   _geom_bond_distance' +
     1936                         '\n   _geom_bond_site_symmetry_1' +
     1937                         '\n   _geom_bond_site_symmetry_2' +
     1938                         '\n   _geom_bond_publ_flag')
     1939                    WriteCIFitem(self.fp, line)
     1940
     1941            # loop over interatomic angles for this phase
     1942            First = True
     1943            for i in sorted(AtomLabels.keys()):
     1944                Dist = DistArray[i]
     1945                for k,j,tup in AngArray[i]:
     1946                    Dj = Dist[j]
     1947                    Dk = Dist[k]
     1948                    line = '  '+PutInCol(AtomLabels[Dj[0]],6)+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[Dk[0]],6)
     1949                    sig = tup[1]
     1950                    if sig == 0: sig = -0.009
     1951                    line += PutInCol(G2mth.ValEsd(tup[0],sig,True),10)
     1952                    line += " {:3d}_".format(G2opcodes.index(Dj[2])+1)
     1953                    for d in Dj[1]:
     1954                        line += "{:1d}".format(d+5)
     1955                    line += "  1_555 "
     1956                    line += " {:3d}_".format(G2opcodes.index(Dk[2])+1)
     1957                    for d in Dk[1]:
     1958                        line += "{:1d}".format(d+5)
     1959                    key = (tuple(Dk[0:3]),i,tuple(Dj[0:3]))
     1960                    if DisAngSel.get(key):
     1961                        line += " no"
     1962                    else:
     1963                        line += " yes"
     1964                    if First:
     1965                        First = False
     1966                        WriteCIFitem(self.fp, '\nloop_' +
     1967                         '\n   _geom_angle_atom_site_label_1' +
     1968                         '\n   _geom_angle_atom_site_label_2' +
     1969                         '\n   _geom_angle_atom_site_label_3' +
     1970                         '\n   _geom_angle' +
     1971                         '\n   _geom_angle_site_symmetry_1' +
     1972                         '\n   _geom_angle_site_symmetry_2' +
     1973                         '\n   _geom_angle_site_symmetry_3' +
     1974                         '\n   _geom_angle_publ_flag')
     1975                    WriteCIFitem(self.fp, line)
     1976
     1977        def WriteSeqOverallPhaseInfo(phasenam,histblk):
     1978            'Write out the phase information for the selected phase for the overall block in a sequential fit'
     1979            WriteCIFitem(self.fp, '# overall phase info for '+str(phasenam) + ' follows')
     1980            phasedict = self.Phases[phasenam] # pointer to current phase info
     1981            WriteCIFitem(self.fp, '_pd_phase_name', phasenam)
     1982
     1983            WriteCIFitem(self.fp, '_symmetry_cell_setting',
     1984                         phasedict['General']['SGData']['SGSys'])
     1985
     1986            if phasedict['General']['Type'] in ['nuclear','macromolecular']:
     1987                spacegroup = phasedict['General']['SGData']['SpGrp'].strip()
     1988                # regularize capitalization and remove trailing H/R
     1989                spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ')
     1990                WriteCIFitem(self.fp, '_symmetry_space_group_name_H-M',spacegroup)
     1991   
     1992                # generate symmetry operations including centering and center of symmetry
     1993                SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps(
     1994                    phasedict['General']['SGData'])
     1995                WriteCIFitem(self.fp, 'loop_\n    _space_group_symop_id\n    _space_group_symop_operation_xyz')
     1996                for i,op in enumerate(SymOpList,start=1):
     1997                    WriteCIFitem(self.fp, '   {:3d}  {:}'.format(i,op.lower()))
     1998            elif phasedict['General']['Type'] == 'magnetic':
     1999                parentSpGrp = phasedict['General']['SGData']['SpGrp'].strip()
     2000                parentSpGrp = parentSpGrp[0].upper() + parentSpGrp[1:].lower().rstrip('rh ')
     2001                WriteCIFitem(self.fp, '_parent_space_group.name_H-M_alt',parentSpGrp)
     2002#                [Trans,Uvec,Vvec] = phasedict['General']['SGData']['fromParent']         #save these
     2003                spacegroup = phasedict['General']['SGData']['MagSpGrp'].strip()
     2004                spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ')
     2005                WriteCIFitem(self.fp, '_space_group_magn.name_BNS',spacegroup)
     2006                WriteCIFitem(self.fp, '_space_group.magn_point_group',phasedict['General']['SGData']['MagPtGp'])
     2007
     2008                # generate symmetry operations including centering and center of symmetry
     2009                SymOpList,offsetList,symOpList,G2oprList,G2opcodes = G2spc.AllOps(
     2010                    phasedict['General']['SGData'])
     2011                SpnFlp = phasedict['General']['SGData']['SpnFlp']
     2012                WriteCIFitem(self.fp, 'loop_\n    _space_group_symop_magn_operation.id\n    _space_group_symop_magn_operation.xyz')
     2013                for i,op in enumerate(SymOpList,start=1):
     2014                    if SpnFlp[i-1] >0:
     2015                        opr = op.lower()+',+1'
     2016                    else:
     2017                        opr = op.lower()+',-1'
     2018                    WriteCIFitem(self.fp, '   {:3d}  {:}'.format(i,opr))
     2019                   
     2020            lam = None
     2021            if 'X' in histblk['Instrument Parameters'][0]['Type'][0]:
     2022                for k in ('Lam','Lam1'):
     2023                    if k in histblk['Instrument Parameters'][0]:
     2024                        lam = histblk['Instrument Parameters'][0][k][0]
     2025                        break
     2026            keV = None
     2027            if lam: keV = 12.397639/lam
     2028            # report cell contents                       
     2029            WriteComposition(self.fp, self.Phases[phasenam], phasenam, self.parmDict, False, keV)
     2030       
     2031        def WriteSeqPhaseVals(phasenam,phasedict,pId,histname):
     2032            'Write out the phase information for the selected phase'
     2033            WriteCIFitem(self.fp, '_pd_phase_name', phasenam)
     2034            cellList,cellSig = getCellwStrain(phasedict,self.seqData,pId,histname)
     2035            T = self.Histograms[histname]['Sample Parameters']['Temperature']
     2036            try:
     2037                T = G2mth.ValEsd(T,-1.0)
     2038            except:
     2039                pass
     2040            WriteCIFitem(self.fp, '_symmetry_cell_setting',
     2041                         phasedict['General']['SGData']['SGSys'])
     2042
     2043            if phasedict['General']['Type'] in ['nuclear','macromolecular']:
     2044                spacegroup = phasedict['General']['SGData']['SpGrp'].strip()
     2045                # regularize capitalization and remove trailing H/R
     2046                spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ')
     2047                WriteCIFitem(self.fp, '_symmetry_space_group_name_H-M',spacegroup)
     2048            WriteCIFitem(self.fp,"_cell_measurement_temperature",T)
     2049            defsigL = 3*[-0.00001] + 3*[-0.001] + [-0.01] # significance to use when no sigma
     2050            prevsig = 0
     2051            for lbl,defsig,val,sig in zip(cellNames,defsigL,cellList,cellSig):
     2052                if sig:
     2053                    txt = G2mth.ValEsd(val,sig)
     2054                    prevsig = -sig # use this as the significance for next value
     2055                else:
     2056                    txt = G2mth.ValEsd(val,min(defsig,prevsig),True)
     2057                WriteCIFitem(self.fp, '_cell_'+lbl,txt)
     2058
     2059            mass = G2mth.getMass(phasedict['General'])
     2060            Volume = cellList[6]
     2061            density = mass/(0.6022137*Volume)
     2062            WriteCIFitem(self.fp, '_exptl_crystal_density_diffrn',
     2063                    G2mth.ValEsd(density,-0.001))
     2064
     2065            # report atom params
     2066            if phasedict['General']['Type'] in ['nuclear','macromolecular']:        #this needs macromolecular variant, etc!
     2067                WriteSeqAtomsNuclear(self.fp, cellList, phasedict, phasenam, histname,
     2068                                         self.seqData, self.OverallParms['Rigid bodies'])
     2069            else:
     2070                print("Warning: no export for sequential "+str(phasedict['General']['Type'])+" coordinates implemented")
     2071#                raise Exception("no export for "+str(phasedict['General']['Type'])+" coordinates implemented")
     2072
     2073            if phasedict['General']['Type'] == 'nuclear':
     2074                WriteSeqDistances(phasenam,histname,phasedict,cellList,self.seqData)
     2075
     2076            # N.B. map info probably not possible w/sequential
     2077#            if 'Map' in phasedict['General'] and 'minmax' in phasedict['General']['Map']:
     2078#                WriteCIFitem(self.fp, '\n# Difference density results')
     2079#                MinMax = phasedict['General']['Map']['minmax']
     2080#                WriteCIFitem(self.fp, '_refine_diff_density_max',G2mth.ValEsd(MinMax[0],-0.009))
     2081#                WriteCIFitem(self.fp, '_refine_diff_density_min',G2mth.ValEsd(MinMax[1],-0.009))
     2082               
    12962083        def WritePhaseInfo(phasenam,quick=True,oneblock=True):
    12972084            'Write out the phase information for the selected phase'
     
    13162103                        pId = phasedict['pId']
    13172104                        hId = self.Histograms[h]['hId']
    1318                         cellList,cellSig = G2strIO.getCellSU(pId,hId,
     2105                        cellList,cellSig = G2stIO.getCellSU(pId,hId,
    13192106                                        phasedict['General']['SGData'],
    13202107                                        self.parmDict,
     
    14122199                WriteAtomsMagnetic(self.fp, self.Phases[phasenam], phasenam,
    14132200                                  self.parmDict, self.sigDict, self.labellist)
    1414 #                self.CloseFile()
    14152201#                raise Exception("no export for "+str(phasedict['General']['Type'])+" coordinates implemented")
    14162202            keV = None             
     
    14302216            WriteComposition(self.fp, self.Phases[phasenam], phasenam, self.parmDict, self.quickmode, keV)
    14312217            if not self.quickmode and phasedict['General']['Type'] == 'nuclear':      # report distances and angles
    1432                 WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList)
     2218                WriteDistances(phasenam)
    14332219            if 'Map' in phasedict['General'] and 'minmax' in phasedict['General']['Map']:
    14342220                WriteCIFitem(self.fp, '\n# Difference density results')
     
    14362222                WriteCIFitem(self.fp, '_refine_diff_density_max',G2mth.ValEsd(MinMax[0],-0.009))
    14372223                WriteCIFitem(self.fp, '_refine_diff_density_min',G2mth.ValEsd(MinMax[1],-0.009))
    1438 
     2224               
    14392225        def Yfmt(ndec,val):
    14402226            'Format intensity values'
     
    14612247                WriteCIFitem(self.fp, '_reflns_d_resolution_high ', G2mth.ValEsd(dmin,-0.009))
    14622248
    1463         def WritePowderData(histlbl):
     2249        def WritePowderData(histlbl,seq=False):
    14642250            'Write out the selected powder diffraction histogram info'
    14652251            histblk = self.Histograms[histlbl]
     
    14932279
    14942280            if not oneblock:
    1495                 if not phasebyhistDict.get(histlbl):
     2281                if seq:
     2282                    pass
     2283                elif not phasebyhistDict.get(histlbl):
    14962284                    WriteCIFitem(self.fp, '\n# No phases associated with this data set')
    14972285                else:
     
    15982386                P = '?'
    15992387            else:
    1600                 P = G2mth.ValEsd(pressure*1000,-0.09,True) # CIF uses kilopascal
     2388                P = G2mth.ValEsd(pressure*1000,-0.09,True) # CIF uses kilopascal (G2 Mpa)
    16012389            WriteCIFitem(self.fp, '_diffrn_ambient_pressure',P)
    16022390
     
    18552643
    18562644        def EditInstNames(event=None):
    1857             'Provide a dialog for editing instrument names'
     2645            'Provide a dialog for editing instrument names; for sequential fit, only need one name'
    18582646            dictlist = []
    18592647            keylist = []
    18602648            lbllist = []
    1861             for hist in self.Histograms:
     2649            for hist in sorted(self.Histograms):
    18622650                if hist.startswith("PWDR"):
    18632651                    key2 = "Sample Parameters"
     
    18732661                if instrname is None:
    18742662                    d['InstrName'] = ''
     2663                if hist.startswith("PWDR") and seqmode: break               
    18752664            return G2G.CallScrolledMultiEditor(
    18762665                self.G2frame,dictlist,keylist,
     
    19602749            for i in sorted(self.powderDict.keys()):
    19612750                G2G.HorizontalLine(cbox,cpnl)
     2751                if seqmode:
     2752                    hist = self.powderDict[i]
     2753                    histblk = self.Histograms[hist]
     2754                    title = 'All Powder datasets'
     2755                    self.seqSmplParms = {}
     2756                    cbox.Add(
     2757                        CIFtemplateSelect(self.cifdefs,
     2758                                      cpnl,'powder',self.seqSmplParms,
     2759                                      EditCIFDefaults,
     2760                                      title,
     2761                                      histblk["Sample Parameters"]['InstrName']),
     2762                        0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL)
     2763                    break
    19622764                hist = self.powderDict[i]
    19632765                histblk = self.Histograms[hist]
     
    22253027            return
    22263028        #===============================================================================
    2227         # the export process for a full CIF starts here
     3029        # setup for sequential fits here
     3030        #===============================================================================
     3031        seqmode = False
     3032        seqHistList = self.G2frame.testSeqRefineMode()
     3033        if seqHistList:
     3034            if self.seqData is None:
     3035                raise Exception('Use Export/Sequential project for sequential refinements')
     3036            phaseWithHist = True   # include the phase in the same block as the histogram
     3037            if len(self.Phases) > 1:
     3038                phaseWithHist = False  # multiple phases per histogram
     3039            seqmode = True
     3040        #===============================================================================
     3041        # the export process for a full CIF starts here (Sequential too)
    22283042        #===============================================================================
    22293043        # load saved CIF author name
     
    22463060            return
    22473061        self.OpenFile()
     3062       
    22483063        #if self.ExportSelect('default'): return
    22493064        # Someday: get restraint & constraint info
     
    22843099            elif instrname.strip() == '':
    22853100                invalid += 1
     3101            if hist.startswith("PWDR") and seqmode: break
    22863102        if invalid:
    22873103            #msg = ""
     
    23683184        self.cifdefs.Destroy()
    23693185        #======================================================================
    2370         # Start writing the CIF - single block
     3186        #---- Start writing the CIF - single block
    23713187        #======================================================================
    23723188        print('Writing CIF output to file '+self.filename+"...")
     
    24213237                writeCIFtemplate(histprm,'single',histprm['InstrName']) # single crystal template
    24223238                WriteSingleXtalData(hist)
     3239        elif seqHistList:
     3240            #---- sequential fit project (multiblock)  ====================
     3241            phasebyhistDict = {} # create a cross-reference to phases by histogram
     3242            for phasenam in sorted(self.Phases.keys()):
     3243                rId = phasedict['ranId']
     3244                if rId in self.CellHistSelection: continue
     3245                self.CellHistSelection[rId] = self._CellSelectHist(phasenam)
     3246            nsteps = 1 + len(self.Phases) + len(self.powderDict) + len(self.xtalDict)
     3247            try:
     3248                dlg = wx.ProgressDialog('CIF progress','starting',nsteps,parent=self.G2frame)
     3249                dlg.CenterOnParent()
     3250
     3251                # publication info
     3252                step = 1
     3253                dlg.Update(step,"Exporting overall section")
     3254                WriteCIFitem(self.fp, '\ndata_'+self.CIFname+'_publ')
     3255                WriteAudit()
     3256                WriteCIFitem(self.fp, '_pd_block_id',
     3257                             str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
     3258                             str(self.shortauthorname) + "|Overall")
     3259                writeCIFtemplate(self.OverallParms['Controls'],'publ') #insert the publication template
     3260                # ``template_publ.cif`` or a modified version
     3261                # overall info
     3262                WriteCIFitem(self.fp, 'data_'+str(self.CIFname)+'_overall')
     3263                WriteOverall('seq')
     3264                hist = self.powderDict[sorted(self.powderDict.keys())[0]]
     3265                instnam = self.Histograms[hist]["Sample Parameters"]['InstrName']
     3266                writeCIFtemplate(self.seqSmplParms,'powder',instnam) # powder template
     3267                instnam = instnam.replace(' ','')
     3268                #============================================================
     3269                if phaseWithHist:
     3270                    WriteCIFitem(self.fp, '# POINTERS TO HISTOGRAM BLOCKS (Phase in histogram block)')
     3271                else:
     3272                    WriteCIFitem(self.fp, '# POINTERS TO HISTOGRAM BLOCKS (Phases pointer in histogram block)')
     3273                datablockidDict = {} # save block names here
     3274                # loop over data blocks
     3275                if len(self.powderDict) + len(self.xtalDict) > 1:
     3276                    loopprefix = ''
     3277                    WriteCIFitem(self.fp, 'loop_   _pd_block_diffractogram_id')
     3278                else:
     3279                    loopprefix = '_pd_block_diffractogram_id'
     3280                for i in sorted(self.powderDict.keys()):
     3281                    hist = self.powderDict[i]
     3282                    j = self.Histograms[hist]['hId']
     3283                    datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
     3284                                             str(self.shortauthorname) + "|" +
     3285                                             instnam + "_hist_"+str(j))
     3286                    WriteCIFitem(self.fp, loopprefix,datablockidDict[hist])
     3287                for i in sorted(self.xtalDict.keys()):
     3288                    hist = self.xtalDict[i]
     3289                    histblk = self.Histograms[hist]
     3290                    instnam = histblk["Instrument Parameters"][0]['InstrName']
     3291                    instnam = instnam.replace(' ','')
     3292                    i = histblk['hId']
     3293                    datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
     3294                                             str(self.shortauthorname) + "|" +
     3295                                             instnam + "_hist_"+str(i))
     3296                    WriteCIFitem(self.fp, loopprefix,datablockidDict[hist])
     3297                # setup and show sequential results table
     3298                tblLabels,tblValues,tblSigs,tblTypes = mkSeqResTable('cif',seqHistList,self.seqData,
     3299                                                    self.Phases,self.Histograms,self.Controls)
     3300                WriteCIFitem(self.fp, '\n# Sequential results table') # (in case anyone can make sense of it)
     3301                WriteCIFitem(self.fp, 'loop_   _gsas_seq_results_col_num _gsas_seq_results_col_label')
     3302                for i,lbl in enumerate(tblLabels):
     3303                    s = PutInCol(str(i),5)
     3304                    if ' ' in lbl:
     3305                        s += '"' + lbl + '"'
     3306                    else:
     3307                        s += lbl
     3308                    WriteCIFitem(self.fp,"  "+s)
     3309                s = 'loop_ '
     3310                linelength = 120
     3311                for i in range(len(tblLabels)):
     3312                    if len(s) > linelength:
     3313                        WriteCIFitem(self.fp,s)
     3314                        s = '  '
     3315                    s += " _gsas_seq_results_val" + str(i)
     3316                WriteCIFitem(self.fp,s)
     3317               
     3318                for r in range(len(tblValues[0])):
     3319                    s = ''
     3320                    for c in range(len(tblLabels)):
     3321                        if len(s) > linelength:
     3322                            WriteCIFitem(self.fp,s)
     3323                            s = '  '
     3324                        sig = None
     3325                        if tblSigs[c] is not None:
     3326                            sig = tblSigs[c][r]
     3327                           
     3328                        if tblValues[c][r] is None:
     3329                            if tblTypes[c] == 'int':
     3330                                wid = 5
     3331                            elif tblTypes[c] == 'str':
     3332                                wid = 10
     3333                            else:
     3334                                wid = 12                               
     3335                            s += PutInCol('.',wid)
     3336                        elif sig is None and ',' in tblTypes[c]:
     3337                            s += PutInCol(
     3338                                ('{{:{}.{}f}}'.format(*tblTypes[c].split(','))).format(tblValues[c][r]),12)
     3339                        elif tblTypes[c] == 'int':
     3340                            s += PutInCol(str(tblValues[c][r]),5)
     3341                        elif tblTypes[c] == 'str':
     3342                            s += PutInCol(str(tblValues[c][r]),10)
     3343                        elif sig is None and ',' in tblTypes[c]:
     3344                            s += PutInCol(
     3345                                ('{{:{}.{}f}}'.format(*tblTypes[c].split(','))).format(tblValues[c][r]),12)
     3346                        elif sig is None and tblTypes[c] == 'float':
     3347                            s += PutInCol('{:.6g}'.format(tblValues[c][r]),12)
     3348                        elif sig:
     3349                            s += PutInCol(G2mth.ValEsd(tblValues[c][r],sig),12)
     3350                        else:
     3351                            s += PutInCol(str(tblValues[c][r]),15)
     3352                    WriteCIFitem(self.fp,s+'\n')
     3353
     3354                # sample template info & info for all phases
     3355
     3356                i = sorted(self.powderDict.keys())[0]
     3357                hist = self.powderDict[i]
     3358                histblk = self.Histograms[hist]
     3359                if phaseWithHist:    # include sample info in overall block
     3360                    phasenam = list(self.Phases.keys())[0]
     3361                    writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template
     3362                    WriteSeqOverallPhaseInfo(phasenam,histblk)
     3363                else:
     3364                    for j,phasenam in enumerate(sorted(self.Phases.keys())):
     3365                        pId = self.Phases[phasenam]['pId']
     3366                        WriteCIFitem(self.fp, '\n#'+78*'=')
     3367                        WriteCIFitem(self.fp, 'data_'+self.CIFname+"_overall_phase"+str(j)+'\n')
     3368                        writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template
     3369                        WriteSeqOverallPhaseInfo(phasenam,histblk)
     3370                       
     3371                for i in sorted(self.powderDict.keys()):
     3372                    hist = self.powderDict[i]
     3373                    hId = self.Histograms[hist]['hId']
     3374                    dlg.Update(step,"Exporting "+hist.strip())
     3375                    histblk = self.Histograms[hist]
     3376                    WriteCIFitem(self.fp, '# Information for histogram '+str(i)+': '+hist)
     3377                    WriteCIFitem(self.fp, '\ndata_'+self.CIFname+"_pwd_"+str(i))
     3378                    WriteCIFitem(self.fp, '_pd_block_id',datablockidDict[hist])
     3379                    if not phaseWithHist:
     3380                        WriteCIFitem(self.fp, '\n# POINTERS TO PHASE BLOCKS')
     3381                        phaseBlockName = {}
     3382
     3383                        wtFrSum = 0.
     3384                        for j,phasenam in enumerate(sorted(self.Phases.keys())):
     3385                            if hist not in self.Phases[phasenam]['Histograms']: continue
     3386                            if not self.Phases[phasenam]['Histograms'][hist]['Use']: continue
     3387                            phFrac = self.Phases[phasenam]['Histograms'][hist]['Scale'][0]
     3388                            phFracKey = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':Scale'
     3389                            phFrac = self.seqData[hist]['parmDict'].get(phFracKey,phFrac)
     3390                            wtFrSum += phFrac * self.Phases[phasenam]['General']['Mass']
     3391                        WriteCIFitem(self.fp, 'loop_ _pd_phase_id _pd_phase_block_id _pd_phase_mass_%')
     3392                        for j,phasenam in enumerate(sorted(self.Phases.keys())):
     3393                            pId = self.Phases[phasenam]['pId']
     3394                            if hist not in self.Phases[phasenam]['Histograms']: continue
     3395                            if not self.Phases[phasenam]['Histograms'][hist]['Use']: continue
     3396                            if ' ' in phasenam:
     3397                                s = PutInCol('"'+phasenam+'"',20)
     3398                            else:
     3399                                s = PutInCol(phasenam,20)
     3400                            phaseBlockName[pId] = datablockidDict[hist]+'_p'+str(j+1)
     3401                            phFrac = self.Phases[phasenam]['Histograms'][hist]['Scale'][0]
     3402                            phFracKey = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':Scale'
     3403                            phFrac = self.seqData[hist]['parmDict'].get(phFracKey,phFrac)
     3404                            wtFr = phFrac * self.Phases[phasenam]['General']['Mass'] / wtFrSum
     3405                            if phFracKey in self.seqData[hist]['varyList']:
     3406                                sig = self.seqData[hist]['sig'][self.seqData[hist]['varyList'].index(phFracKey)]
     3407                                sig *= self.Phases[phasenam]['General']['Mass'] / wtFrSum
     3408                            elif phFracKey in self.seqData[hist]['depParmDict']:
     3409                                sig = self.seqData[hist]['depParmDict'][phFracKey][1]
     3410                                sig *= self.Phases[phasenam]['General']['Mass'] / wtFrSum
     3411                            else:
     3412                                sig = -0.0001
     3413                            WriteCIFitem(self.fp, "  "+ s + " " + phaseBlockName[pId] + "  " + G2mth.ValEsd(wtFr,sig))
     3414                        PP = FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])
     3415                        PP += '\n'
     3416                        WriteCIFitem(self.fp, '_pd_proc_ls_profile_function',PP)
     3417               
     3418                    WritePowderData(hist,seq=True) # write background, data & reflections, some instrument & sample terms
     3419                    WriteCIFitem(self.fp, '\n# PHASE INFO FOR HISTOGRAM '+hist)
     3420                    for j,phasenam in enumerate(sorted(self.Phases.keys())):
     3421                        pId = self.Phases[phasenam]['pId']
     3422                        if hist not in self.Phases[phasenam]['Histograms']: continue
     3423                        if not self.Phases[phasenam]['Histograms'][hist]['Use']: continue
     3424                        WriteCIFitem(self.fp, '\n# phase info for '+str(phasenam) + ' follows')
     3425                        if not phaseWithHist:
     3426                            WriteCIFitem(self.fp, 'data_'+self.CIFname+"_hist"+str(i)+"_phase"+str(j))
     3427                            WriteCIFitem(self.fp, '_pd_block_id',phaseBlockName[pId])
     3428                            WriteCIFitem(self.fp, '')
     3429
     3430                        WriteSeqPhaseVals(phasenam,self.Phases[phasenam],pId,hist)
     3431
     3432                        # preferred orientation & profile terms
     3433                        if self.ifPWDR:
     3434                            #SH = FormatSH(phasenam)     # TODO: needs to use seqData
     3435                            #MD = FormatHAPpo(phasenam)  # TODO: switch to seqData
     3436                            #if SH and MD:
     3437                            #    WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + '\n' + MD)
     3438                            #elif SH or MD:
     3439                            #    WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', SH + MD)
     3440                            #else:
     3441                            #    WriteCIFitem(self.fp, '_pd_proc_ls_pref_orient_corr', 'none')
     3442                            # report sample profile terms for all histograms with current phase
     3443                            if phaseWithHist:
     3444                                PP = FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])
     3445                                PP += '\n'
     3446                            else:
     3447                                PP = ''
     3448                            PP += FormatPhaseProfile(phasenam,hist)
     3449                            WriteCIFitem(self.fp, '\n_pd_proc_ls_profile_function',PP)
     3450            finally:
     3451                dlg.Destroy()
    24233452        else:
    2424             #=== multiblock: multiple phases and/or histograms ====================
     3453            #---- multiblock: multiple phases and/or histograms ====================
    24253454            for phasenam in sorted(self.Phases.keys()):
    24263455                rId = phasedict['ranId']
     
    24873516            #============================================================
    24883517            # loop over phases, exporting them
    2489             phasebyhistDict = {} # create a cross-reference to phases by histogram
    24903518            for j,phasenam in enumerate(sorted(self.Phases.keys())):
    24913519                step += 1
     
    25363564                    dlg.Update(step,"Exporting "+hist.strip())
    25373565                    WriteCIFitem(self.fp, '\ndata_'+self.CIFname+"_pwd_"+str(i))
     3566                    WriteCIFitem(self.fp, '# Information for histogram '+str(i)+': '+hist)
    25383567                    #instnam = histblk["Sample Parameters"]['InstrName']
    25393568                    # report instrumental profile terms
    25403569                    WriteCIFitem(self.fp, '_pd_proc_ls_profile_function',
    25413570                        FormatInstProfile(histblk["Instrument Parameters"],histblk['hId']))
    2542                     WriteCIFitem(self.fp, '# Information for histogram '+str(i)+': '+hist)
    25433571                    WriteCIFitem(self.fp, '_pd_block_id',datablockidDict[hist])
    25443572                    histprm = self.Histograms[hist]["Sample Parameters"]
     
    25843612
    25853613        WriteCIFitem(self.fp, '#--' + 15*'eof--' + '#')
    2586         #self.CloseFile()
    25873614        print("...export completed")
    25883615        print('file '+self.fullpath)
     
    26033630        self.exporttype = ['project']
    26043631
    2605     def Exporter(self,event=None):
     3632    def Exporter(self,event=None,seqData=None,Controls=None):
     3633        self.seqData = seqData
     3634        self.Controls = Controls
    26063635        self.InitExport(event)
    26073636        # load all of the tree into a set of dicts
     
    26093638        self._Exporter(event=event)
    26103639        self.CloseFile()
    2611 
    2612     # def Writer(self,hist,mode='w'):
    2613     #     '''Used for full project CIF export of a sequential fit.
    2614     #     TODO: Needs extensive work
    2615     #     '''
    2616     #     # set the project file name
    2617     #     self.CIFname = os.path.splitext(
    2618     #         os.path.split(self.G2frame.GSASprojectfile)[1]
    2619     #         )[0]+'_'+hist
    2620     #     self.CIFname = self.CIFname.replace(' ','')
    2621     #     self.OpenFile(mode=mode)
    2622     #     self._Exporter(IncludeOnlyHist=hist)
    2623     #     if mode == 'w':
    2624     #         print('CIF written to file '+self.fullpath)
    2625     #     self.CloseFile()
    26263640
    26273641class ExportPhaseCIF(ExportCIF):
Note: See TracChangeset for help on using the changeset viewer.