Changeset 5317


Ignore:
Timestamp:
Jul 28, 2022 2:03:20 PM (17 months ago)
Author:
toby
Message:

fullrmc updates

Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIdataGUI.py

    r5312 r5317  
    63826382        # PWDR & SASD
    63836383        G2G.Define_wxId('wxID_PWDANALYSIS','wxID_PWDCOPY','wxID_PLOTCTRLCOPY','wxID_MERGEHKL',
    6384             'wxID_PWDHKLPLOT', 'wxID_PWD3DHKLPLOT','wxID_3DALLHKLPLOT','wxID_1DHKLSTICKPLOT','wxID_CSVFROMTABLE')           
     6384            'wxID_PWDHKLPLOT', 'wxID_PWD3DHKLPLOT','wxID_3DALLHKLPLOT','wxID_1DHKLSTICKPLOT')           
    63856385        self.PWDRMenu = wx.MenuBar()
    63866386        self.PrefillDataMenu(self.PWDRMenu)
     
    68796879       
    68806880        #Phase / fullrmc & RMCprofile (Reverse Monte Carlo method) tab
    6881         G2G.Define_wxId('wxID_SETUPRMC','wxID_RUNRMC','wxID_VIEWRMC','wxID_STOPRMC', )       
     6881        G2G.Define_wxId('wxID_SETUPRMC','wxID_RUNRMC','wxID_VIEWRMC','wxID_STOPRMC',
     6882                            'wxID_ATOMSRMC', 'wxID_SUPERRMC')       
    68826883        self.FRMCMenu = wx.MenuBar()
    68836884        self.PrefillDataMenu(self.FRMCMenu)
     
    68876888        self.FRMCDataEdit.Append(G2G.wxID_SETUPRMC,'Setup RMC','Setup new fullrmc or RMCprofile file')
    68886889        self.FRMCDataEdit.Append(G2G.wxID_RUNRMC,'Execute','Run fullrmc or RMCprofile file')
    6889         self.FRMCDataEdit.Append(G2G.wxID_STOPRMC,'Stop run','Stop fullrmc run')
     6890        #self.FRMCDataEdit.Append(G2G.wxID_STOPRMC,'Stop run','Stop fullrmc run')
    68906891        self.FRMCDataEdit.Append(G2G.wxID_VIEWRMC,'Plot','View fullrmc or RMCprofile results')
     6892        self.FRMCDataEdit.Append(G2G.wxID_SUPERRMC,'Load Supercell','Load fullrmc results as a supercell')
     6893        self.FRMCDataEdit.Append(G2G.wxID_ATOMSRMC,'Superimpose into cell','Load fullrmc results folded into original cell')
    68916894        self.PostfillDataMenu()
    68926895       
  • trunk/GSASIIphsGUI.py

    r5313 r5317  
    47024702# fullrmc stuff TODO:
    47034703#  1) need to implement swapping in scripts
    4704 #  2) fullrmc docs/installation in files
    4705 #     file:///Users/toby/G2/trunk/help/gsasII-phase.html#Phase-RMC
    4706 #     file:///Users/toby/G2/trunk/help/gsasII.html#fullrmc
    4707 #     sources/packages.rst.txt
    4708 # add files from https://drive.google.com/drive/folders/10hxmQviKoMaW9R4MxsaiDyPSretxr_P7 into binaries?
    4709 #  3) when GSASIIpwd.findfullrmc fails, should trigger message with link to above
    4710 #  4) fullrmc tutorials
    4711 #  5) G2pwd.findfullrmc: look at error msg & help link
    4712 
    4713     def UpdateRMC():
     4704#  2) fullrmc tutorials
     4705
     4706    def UpdateRMC(event=None):
    47144707        ''' Present the controls for running fullrmc, RMCProfile or PDFfit
    47154708        '''
     
    52545247            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_RUNRMC,True)
    52555248            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_VIEWRMC,True)
     5249            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_ATOMSRMC,True)
     5250            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_SUPERRMC,True)
    52565251            #mainSizer.Add(wx.StaticText(G2frame.FRMC,label=' fullrmc big box starting pdb file preparation:'),0)
    52575252
     
    54995494            mainSizer.Add(wx.StaticText(G2frame.FRMC,label='Geometry constraints && restraints'),0)
    55005495            distBox = wx.BoxSizer(wx.HORIZONTAL)
    5501             distBox.Add(wx.StaticText(G2frame.FRMC,label=' Distance constraints, weight: :'),0,WACV)       
    5502             distBox.Add(G2G.ValidatedTxtCtrl(G2frame.FRMC,RMCPdict,'Bond Weight',xmin=0.,xmax=100.,size=(50,25)),0,WACV)
     5496            distBox.Add(wx.StaticText(G2frame.FRMC,label='Distance constraints'),0,WACV)
     5497            # weights removed for now
     5498            #distBox.Add(wx.StaticText(G2frame.FRMC,label=', distance weight:'),0,WACV)       
     5499            #distBox.Add(G2G.ValidatedTxtCtrl(G2frame.FRMC,RMCPdict,'Bond Weight',xmin=0.,xmax=100.,size=(50,25)),0,WACV)
    55035500            distBox.Add(wx.StaticText(G2frame.FRMC,label=' min contact dist: '),0,WACV)
    5504             distBox.Add(G2G.ValidatedTxtCtrl(G2frame.FRMC,RMCPdict,'min Contact',xmin=0.,xmax=4.,size=(50,25)),0,WACV)           
     5501            distBox.Add(G2G.ValidatedTxtCtrl(G2frame.FRMC,RMCPdict,'min Contact',xmin=0.,xmax=4.,size=(50,25)),0,WACV)
     5502           
     5503            RMCPdict['useBondConstraints'] = RMCPdict.get('useBondConstraints',True)
     5504            distBox.Add(wx.StaticText(G2frame.FRMC,label='  Use bond constraints? '),0,WACV)
     5505            distBox.Add(G2G.G2CheckBox(G2frame.FRMC,'',RMCPdict,'useBondConstraints',OnChange=UpdateRMC),
     5506                            0,WACV)
    55055507            mainSizer.Add(distBox,0)
    5506             mainSizer.Add(GetPairSizer(G2frame.FRMC,RMCPdict),0)
    5507 
    5508             mainSizer.Add((-1,10))
     5508           
     5509            if RMCPdict['useBondConstraints']:
     5510                mainSizer.Add(GetPairSizer(G2frame.FRMC,RMCPdict),0)
     5511                mainSizer.Add((-1,10))
    55095512            angBox = wx.BoxSizer(wx.HORIZONTAL)
    5510             angBox.Add(wx.StaticText(G2frame.FRMC,label=' A-B-C angle restraints, weight: '),0,WACV)
    5511             angBox.Add(G2G.ValidatedTxtCtrl(G2frame.FRMC,RMCPdict,'Angle Weight',xmin=0.,xmax=100.,size=(50,25)),0,WACV)
     5513            angBox.Add(wx.StaticText(G2frame.FRMC,label='A-B-C angle restraints'),0,WACV)
     5514            # weights removed for now
     5515            #angBox.Add(wx.StaticText(G2frame.FRMC,label=', angle weight:'),0,WACV)       
     5516            #angBox.Add(G2G.ValidatedTxtCtrl(G2frame.FRMC,RMCPdict,'Angle Weight',xmin=0.,xmax=100.,size=(50,25)),0,WACV)
    55125517            angBox.Add((20,-1))
    55135518            angAdd = wx.Button(G2frame.FRMC,label='Add',style=wx.BU_EXACTFIT)
     
    55175522            if len(RMCPdict['Angles']):
    55185523                mainSizer.Add(GetAngleSizer(),0)
     5524            RMCPdict['Groups'] = RMCPdict.get('Groups',[])
     5525            def OnAddGroup(event):
     5526                index = len(RMCPdict['Groups'])
     5527                RMCPdict['Groups'].append([])
     5528                GroupEditor(index)
     5529            def OnDelGroup(event):
     5530                index = event.EventObject.index
     5531                del RMCPdict['Groups'][index]
     5532                wx.CallAfter(UpdateRMC)
     5533            def OnEdtGroup(event):
     5534                index = event.EventObject.index
     5535                GroupEditor(index)
     5536            def GroupEditor(index):
     5537                cx,ct,cs,cia = data['General']['AtomPtrs']
     5538                atomlbs = [a[ct-1] for a in data['Atoms']]
     5539                dlg = G2G.G2MultiChoiceDialog(G2frame.FRMC,'Atom Selector',
     5540                            'Select atoms to include in group',atomlbs,selected=RMCPdict['Groups'][index])
     5541                if dlg.ShowModal() == wx.ID_OK:
     5542                    RMCPdict['Groups'][index] = dlg.GetSelections()
     5543                dlg.Destroy()
     5544                #breakpoint()
     5545                if len(RMCPdict['Groups'][index]) == 0:
     5546                    del RMCPdict['Groups'][index]
     5547                wx.CallAfter(UpdateRMC)
     5548            if len(RMCPdict['Groups']) == 0:
     5549                grpAdd = wx.Button(G2frame.FRMC,label='Define atom group',style=wx.BU_EXACTFIT)
     5550                grpAdd.Bind(wx.EVT_BUTTON,OnAddGroup)
     5551                mainSizer.Add(grpAdd,0)
     5552            else:
     5553                grpBox = wx.BoxSizer(wx.HORIZONTAL)
     5554                grpBox.Add(wx.StaticText(G2frame.FRMC,label='Atom Groups:  '),0,WACV)       
     5555                grpAdd = wx.Button(G2frame.FRMC,label='Add group',style=wx.BU_EXACTFIT)
     5556                grpAdd.Bind(wx.EVT_BUTTON,OnAddGroup)
     5557                RMCPdict['GroupMode'] = RMCPdict.get('GroupMode',0)
     5558                grpBox.Add(grpAdd,0,WACV)
     5559                grpBox.Add(wx.StaticText(G2frame.FRMC,
     5560                            label='  Group refinement mode: '),0,WACV)       
     5561                grpBox.Add(G2G.EnumSelector(G2frame.FRMC,RMCPdict,'GroupMode',
     5562                        ('Rotate & Translate','Rotate only','Translate only'),
     5563                        [0,1,2]),0,WACV)
     5564                mainSizer.Add(grpBox,0)
     5565                for i,g in enumerate(RMCPdict['Groups']):
     5566                    grpBox = wx.BoxSizer(wx.HORIZONTAL)
     5567                    grpBox.Add((20,-1))
     5568                    grpBox.Add(wx.StaticText(G2frame.FRMC,label='Group #'+str(i+1)),0,WACV)       
     5569                    grpBox.Add((4,-1))
     5570                    grpdel = wx.Button(G2frame.FRMC,label='Del',style=wx.BU_EXACTFIT)
     5571                    grpdel.Bind(wx.EVT_BUTTON,OnDelGroup)
     5572                    grpdel.index = i
     5573                    grpBox.Add(grpdel,0,WACV)
     5574                    grpadd = wx.Button(G2frame.FRMC,label='Edit',style=wx.BU_EXACTFIT)
     5575                    grpadd.Bind(wx.EVT_BUTTON,OnEdtGroup)
     5576                    grpadd.index = i
     5577                    grpBox.Add(grpadd,0,WACV)
     5578                    msg = ' Contains atoms: '
     5579                    for i,n in enumerate(g):
     5580                        if i+1 == len(g):
     5581                            msg += ' && '
     5582                        elif i > 0:
     5583                            msg += ', '
     5584                        msg += str(i)
     5585                    grpBox.Add(wx.StaticText(G2frame.FRMC,label=msg),0,WACV)       
     5586                    mainSizer.Add(grpBox,0)
    55195587
    55205588            # Torsions are difficult to implement. Need to be internal to a unit cell & named with fullrmc
     
    62266294####start of UpdateRMC           
    62276295        G2frame.GetStatusBar().SetStatusText('',1)
     6296        G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_ATOMSRMC,False)
     6297        G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_SUPERRMC,False)
    62286298        if G2frame.RMCchoice == 'RMCProfile':
    62296299            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_SETUPRMC,True)
    62306300            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_RUNRMC,True)
    62316301            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_VIEWRMC,True)
    6232             G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_STOPRMC,False)
     6302            #G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_STOPRMC,False)
    62336303        elif G2frame.RMCchoice == 'fullrmc':
    62346304            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_SETUPRMC,False)
    62356305            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_RUNRMC,False)
    62366306            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_VIEWRMC,False)
    6237             G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_STOPRMC,False)
     6307            #G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_STOPRMC,False)
     6308            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_ATOMSRMC,True)
     6309            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_SUPERRMC,True)
    62386310        try:
    62396311            if G2frame.FRMC.GetSizer():
     
    62486320        runFile = ' '
    62496321        choice = ['RMCProfile','fullrmc','PDFfit']
     6322        topSizer = wx.BoxSizer(wx.HORIZONTAL)
    62506323        RMCsel = wx.RadioBox(G2frame.FRMC,-1,' Select RMC method:',choices=choice)
    62516324        RMCsel.SetStringSelection(G2frame.RMCchoice)
    62526325        RMCsel.Bind(wx.EVT_RADIOBOX, OnRMCselect)
    6253         mainSizer.Add(RMCsel,0)
     6326        topSizer.Add(RMCsel,0)
     6327        topSizer.Add((20,0))
     6328        txt = wx.StaticText(G2frame.FRMC,
     6329            label=' NB: if you change any of the entries below, you must redo the Operations/Setup RMC step above to apply them before doing Operations/Execute')
     6330        txt.Wrap(400)
     6331        topSizer.Add(txt,0)
     6332        mainSizer.Add(topSizer,0)
    62546333        RMCmisc['RMCnote'] = wx.StaticText(G2frame.FRMC)
    62556334        mainSizer.Add(RMCmisc['RMCnote'])
    6256         G2G.HorizontalLine(mainSizer,G2frame.FRMC)
    6257         mainSizer.Add(wx.StaticText(G2frame.FRMC,
    6258             label=' NB: if you change any of the entries below, you must redo the Operations/Setup RMC step \n above to apply them before doing Operations/Execute'),0)
    62596335        G2G.HorizontalLine(mainSizer,G2frame.FRMC)
    62606336        if G2frame.RMCchoice == 'fullrmc':
     
    62756351            RMCmisc['RMCnote'].SetLabel('PDFfit may not be installed or operational')
    62766352        elif G2frame.RMCchoice == 'fullrmc' and G2pwd.findfullrmc() is None:
    6277             dlg = wx.MessageDialog(G2frame,
    6278                     'The fullrmc code is not installed or could not be'
    6279                     ' located. Do you want help information on fullrmc?',
    6280                     'Install info',
    6281                     wx.YES|wx.NO)
     6353            msg = ('The fullrmc Python image is not found.'+
     6354                    ' Do you want it installed for you from '+
     6355        'https://github.com/bachiraoun/fullrmc/tree/master/standalones?'+
     6356                    '\n\n40-50 Mb (download times vary)')
     6357            dlg = wx.MessageDialog(G2frame,msg,'Install fullrmc',wx.YES|wx.NO)
    62826358            try:
    62836359                dlg.CenterOnParent()
     
    62866362                dlg.Destroy()
    62876363            if result == wx.ID_YES:
    6288                 G2G.ShowHelp('fullrmc',G2frame)
     6364                wx.BeginBusyCursor()
     6365                res = G2pwd.fullrmcDownload()
     6366                wx.EndBusyCursor()
     6367            else:
     6368                RMCmisc['RMCnote'].SetLabel('Note that fullrmc is not installed or was not located')
    62896369            return mainSizer
    62906370       
     
    62986378            pName = pName.replace(' ','_')
    62996379            G2frame.dataWindow.FRMCDataEdit.Enable(G2G.wxID_RUNRMC,True)
    6300             #--------- debug stuff
    6301             # import imp
    6302             # imp.reload(G2pwd)
    6303             # grpDict = [[0] for i in data['Atoms']] # debug: all atoms in 1st group
    6304             # atomlist,coordlist = G2pwd.MakefullrmcSupercell(data,RMCPdict,grpDict)
    6305             # fil = os.path.join(os.path.split(G2frame.GSASprojectfile)[0],
    6306             #                        'testatoms.py')
    6307             # fp = open(fil,'w')
    6308             # fp.write('atomlist = [  # [element, label, grouplist]\n')
    6309             # for i in atomlist:
    6310             #     fp.write('  '+str(i)+',\n')
    6311             # fp.write(' ] # atomlist\n\n')
    6312             # fp.write('coordlist = [     # (sym#, cell#, atom#, [ortho coords],)\n')
    6313             # for i in coordlist:
    6314             #     fp.write('  '+str(i)+',\n')
    6315             # fp.write(' ] # coordlist\n')
    6316             # fp.write('cell = ' + str(data['General']['Cell'][1:7]) + '\n')
    6317             # fp.write('supercell = ' + str(RMCPdict['SuperCell']) + '\n')
    6318             # # compute bounding box coordinates
    6319             # bbox = []
    6320             # A,B = G2lat.cell2AB(data['General']['Cell'][1:7])
    6321             # for i in range(3):
    6322             #     for val in int(0.5-RMCPdict['SuperCell'][i]/2),int(1+RMCPdict['SuperCell'][0]/2):
    6323             #         fpos = [0,0,0]
    6324             #         fpos[i] = val
    6325             #         bbox.append(np.inner(A,fpos))
    6326             # fp.write('bboxlist = [     # orthogonal coordinate for supercell corners\n')
    6327             # for i in bbox:
    6328             #     fp.write('  '+str(list(i))+',\n')
    6329             # fp.write(' ] # bboxlist\n\n')
    6330             # fp.close()
    6331             # print('file',fil,'written with',len(coordlist),'atoms')
    6332             # #breakpoint()
    6333             # return
    6334             #--------- debug stuff
    63356380            if RMCPdict['Swaps']:
    63366381                wx.MessageDialog(G2frame, G2G.StripIndents(
     
    63386383                        Edit the script by hand before using.''',True),
    63396384                        'No swaps yet',wx.OK).ShowModal()
    6340             # debug stuff
    6341             #if GSASIIpath.GetConfigValue('debug'):
    6342             #    print('reloading',G2pwd)
    6343             #    import imp
    6344             #    imp.reload(G2pwd)
    6345             # end debug stuff           
     6385            #--------- debug stuff
     6386            # if GSASIIpath.GetConfigValue('debug'):
     6387            #     print('reloading',G2pwd)
     6388            #     import imp
     6389            #     imp.reload(G2pwd)
     6390            #--------- end debug stuff
    63466391            rname = G2pwd.MakefullrmcRun(pName,data,RMCPdict)
    63476392            print('build of fullrmc file {} completed'.format(rname))
     
    67766821            RunPDFfit(event)
    67776822           
    6778     def OnStopRMC(event):
    6779         pass
     6823    # def OnStopRMC(event):
    67806824    #     if G2frame.RMCchoice == 'fullrmc':
    67816825    #         generalData = data['General']
     
    67946838    #             print('failed, msg=',msg)
    67956839     
     6840    def OnLoadRMC(event):
     6841        '''Used to load the output from fullrmc with all atoms placed in the
     6842        original cell
     6843        '''
     6844        fullrmcLoadPhase(super=False)
     6845    def OnLoadRMCsuper(event):
     6846        '''Used to load the output from fullrmc with atoms in the simulation
     6847        supercell cell
     6848        '''
     6849        fullrmcLoadPhase(super=True)
     6850    def fullrmcLoadPhase(super):
     6851        '''Used to load the output from fullrmc. Creates a new phase,
     6852        reads all atoms & converts coordinates to fractional.
     6853        If super is False all atoms placed in the original cell.
     6854
     6855        Called from :func:`OnLoadRMC` or :func:`OnLoadRMCsuper` from
     6856        the RMC tab Operations menu commands 'Superimpose into cell'
     6857        and 'Load Supercell'.
     6858        '''
     6859        if G2frame.RMCchoice != 'fullrmc':
     6860            print('fullrmcLoadPhase: How did this happen?')
     6861            return
     6862        # create a new phase
     6863        phId = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Phases')
     6864        phaseRIdList,usedHistograms = G2frame.GetPhaseInfofromTree()
     6865        phaseNameList = list(usedHistograms.keys()) # phase names in use
     6866        PhaseName = G2obj.MakeUniqueLabel(data['General']['Name']+'_fullrmc',phaseNameList)
     6867        psub = G2frame.GPXtree.AppendItem(parent=phId,text=PhaseName)
     6868        E,SGData = G2spc.SpcGroup('P 1')
     6869        G2frame.GPXtree.SetItemPyData(psub,G2obj.SetNewPhase(Name=PhaseName,SGData=SGData))
     6870        newPhase = G2frame.GPXtree.GetItemPyData(psub)
     6871        # add a restraint tree entry
     6872        subr = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Restraints')
     6873        G2frame.GPXtree.GetItemPyData(subr).update({PhaseName:{}})
     6874        # read in info from file
     6875        pName = (G2frame.GSASprojectfile.split('.')[0] + '-'
     6876                     + data['General']['Name'])
     6877        pName = pName.replace(' ','_')
     6878        with open(pName+'-fullrmc.atoms','r') as fp:
     6879            cell = [float(i) for i in fp.readline().split(':')[1].split()]
     6880            supercell = [int(i) for i in fp.readline().split(':')[1].split()]
     6881            if super:
     6882                for i in range(3): cell[i] *= supercell[i]
     6883            # set cell & volume
     6884            newPhase['General']['Cell'][1:7] = cell
     6885            newPhase['General']['Cell'][7] = G2lat.calc_V(G2lat.cell2A(cell))
     6886            A,B = G2lat.cell2AB(cell)
     6887            # add atoms
     6888            for line in fp:
     6889                Name,El,ox,oy,oz = line.split()
     6890                oxyz = [float(i) for i in (ox,oy,oz)]
     6891                if super:
     6892                    (x,y,z) = np.inner(B,oxyz)
     6893                else:
     6894                    (x,y,z),disp = G2spc.MoveToUnitCell(np.inner(B,oxyz))
     6895                atId = ran.randint(0,sys.maxsize)
     6896                newPhase['Atoms'].append([Name,El,'',x,y,z,1.,'1',1,'I',0.01,0,0,0,0,0,0,atId])
     6897
     6898        SetupGeneral()  # index elements
     6899       
     6900        #wx.CallAfter(G2frame.GPXtree.SelectItem,psub) # should call SelectDataT
     6901        #breakpoint()
     6902       
    67966903    def OnViewRMC(event):
    67976904        if G2frame.RMCchoice == 'fullrmc':
     
    1442714534        G2frame.Bind(wx.EVT_MENU, OnRunRMC, id=G2G.wxID_RUNRMC)
    1442814535        G2frame.Bind(wx.EVT_MENU, OnViewRMC, id=G2G.wxID_VIEWRMC)
    14429         G2frame.Bind(wx.EVT_MENU, OnStopRMC, id=G2G.wxID_STOPRMC)
     14536        #G2frame.Bind(wx.EVT_MENU, OnStopRMC, id=G2G.wxID_STOPRMC)
     14537        G2frame.Bind(wx.EVT_MENU, OnLoadRMC, id=G2G.wxID_ATOMSRMC)
     14538        G2frame.Bind(wx.EVT_MENU, OnLoadRMCsuper, id=G2G.wxID_SUPERRMC)
    1443014539        # ISODISTORT
    1443114540        FillSelectPageMenu(TabSelectionIdDict, G2frame.dataWindow.ISODData)
  • trunk/GSASIIpwd.py

    r5316 r5317  
    31793179        else:
    31803180            lookfor = "fullrmc5*64bit"
    3181         fl = glob.glob(lookfor)
     3181        fl = glob.glob(os.path.join(p,lookfor))
    31823182        if len(fl) > 0:
    31833183            fullrmc_exe = os.path.abspath(sorted(fl)[0])
     
    31853185                print('fullrmc found as',fullrmc_exe)
    31863186            return fullrmc_exe
     3187
     3188def fullrmcDownload():
     3189    '''Downloads the fullrmc executable from Bachir's site to the current
     3190    GSAS-II binary directory.
     3191
     3192    Does some error checking.
     3193    '''
     3194    import os
     3195    import requests
     3196    import platform
     3197    if platform.architecture()[0] != '64bit':
     3198        return "fullrmc is only available for 64 bit machines. This is 32 bit"
     3199    setXbit = True
     3200    if sys.platform == "darwin":
     3201        URL = "https://github.com/bachiraoun/fullrmc/raw/master/standalones/fullrmc500_3p8p6_macOS-10p16-x86_64-i386-64bit"
     3202    elif sys.platform == "win32":
     3203        setXbit = False
     3204        URL = "https://github.com/bachiraoun/fullrmc/raw/master/standalones/fullrmc500_3p8p10_Windows-10-10p0p19041-SP0.exe"
     3205    else:
     3206        if 'aarch' in platform.machine() or 'arm' in platform.machine():
     3207            return "Sorry, fullrmc is only available for Intel-compatible machines."
     3208        URL = "https://github.com/bachiraoun/fullrmc/raw/master/standalones/fullrmc500_3p8p5_Linux-4p19p121-linuxkit-x86_64-with-glibc2p29"
     3209   
     3210    GSASIIpath.SetBinaryPath()
     3211    fil = os.path.join(GSASIIpath.binaryPath,os.path.split(URL)[1])
     3212    print('Starting installation of fullrmc\nDownloading from',
     3213              'https://github.com/bachiraoun/fullrmc/tree/master/standalones',
     3214              '\nCreating '+fil,
     3215              '\nThis may take a while...')
     3216    open(fil, "wb").write(requests.get(URL).content)
     3217    print('...Download completed')
     3218    if setXbit:
     3219        import stat
     3220        os.chmod(fil, os.stat(fil).st_mode | stat.S_IEXEC)
     3221    return ''
    31873222
    31883223def findPDFfit():
     
    35863621        return newParms,Rwp
    35873622
    3588 def MakefullrmcSupercell(Phase,RMCPdict,grpDict=[]):
     3623def MakefullrmcSupercell(Phase,RMCPdict):
    35893624    '''Create a fullrmc supercell from GSAS-II
    35903625
     
    36073642    for i,atom in enumerate(Phase['Atoms']):
    36083643        el = ''.join([i for i in atom[ct] if i.isalpha()])
    3609         atomlist.append([el, atom[ct-1], grpDict[i]])
     3644        grps = [j for j,g in enumerate(RMCPdict.get('Groups',[])) if i in g]
     3645        atomlist.append((el, atom[ct-1], grps))
    36103646    # create a list of coordinates with symmetry & unit cell translation duplicates
    36113647    coordlist = []
     
    36603696import pickle
    36613697import types
     3698import copy
    36623699import numpy as np
    36633700import matplotlib as mpl
    36643701import fullrmc
     3702from pdbparser import pdbparser
     3703from pdbparser.Utilities.Database import __ATOM__
    36653704from fullrmc.Core import Collection
    36663705from fullrmc.Engine import Engine
     
    36743713from fullrmc.Constraints.DihedralAngleConstraints import DihedralAngleConstraint
    36753714from fullrmc.Generators.Swaps import SwapPositionsGenerator
     3715from fullrmc.Core.MoveGenerator import MoveGeneratorCollector
     3716from fullrmc.Generators.Translations import TranslationGenerator
     3717from fullrmc.Generators.Rotations import RotationGenerator
     3718
    36763719# utility routines
    36773720def writeHeader(ENGINE,statFP):
     
    37163759    lens.extend( [ts/np.linalg.norm(a), ts/np.linalg.norm(c)] )
    37173760    return min(lens)
     3761
     3762def makepdb(atoms, coords, bbox=None):
     3763    'creates a supercell directly from atom info'
     3764    # used when ENGINE.build_crystal_set_pdb is not called
     3765    prevcell = None
     3766    rec = copy.copy(__ATOM__)
     3767    rec['residue_name'] = 'MOL'
     3768    records = []
     3769    seqNum  = 0
     3770    segId   = '0'
     3771    groups = {}
     3772    for symcell in set([(sym,cell) for sym,cell,atm,xyz in coords]):
     3773        seqNum += 1
     3774        if seqNum == 9999:
     3775            seqNum = 1
     3776            segId  = str(int(segId) + 1)
     3777        for i,(sym,cell,atm,(x,y,z)) in enumerate(coords):
     3778            if (sym,cell) != symcell: continue
     3779            rec   = copy.copy(rec)
     3780            for grp in atoms[atm][2]:
     3781                if (sym,cell) not in groups:
     3782                    groups[(sym,cell)] = {}
     3783                if grp not in groups[(sym,cell)]:
     3784                    groups[(sym,cell)][grp] = [len(records)]
     3785                else:
     3786                    groups[(sym,cell)][grp].append(len(records))
     3787            rec['coordinates_x']      = x
     3788            rec['coordinates_y']      = y
     3789            rec['coordinates_z']      = z
     3790            rec['element_symbol']     = atoms[atm][0]
     3791            rec['atom_name']          = atoms[atm][1]
     3792            rec['sequence_number']    = seqNum
     3793            rec['segment_identifier'] = segId
     3794            records.append(rec)
     3795    # create pdb
     3796    pdb = pdbparser()
     3797    pdb.records = records
     3798    if groups:
     3799        return pdb,[groups[j][i] for j in groups for i in groups[j]]
     3800    else:
     3801        return pdb,[]
    37183802'''
    37193803    rundata += '''
     
    37283812    rundata += '# setup structure\n'
    37293813    rundata += 'cell = ' + str(cell) + '\n'
    3730     rundata += "SymOpList = "+str([i.lower() for i in SymOpList]) + '\n'
    3731     rundata += 'atomList = ' + str(atomsList).replace('],','],\n  ') + '\n'
    37323814    rundata += 'supercell = ' + str(RMCPdict['SuperCell']) + '\n'
     3815    rundata += '\n# define structure info\n'
     3816    if RMCPdict.get('Groups',[]):
     3817        # compute bounding box coordinates
     3818        bbox = []
     3819        A,B = G2lat.cell2AB(cell)
     3820        for i in range(3):
     3821            for val in int(0.5-RMCPdict['SuperCell'][i]/2),int(1+RMCPdict['SuperCell'][0]/2):
     3822                fpos = [0,0,0]
     3823                fpos[i] = val
     3824                bbox.append(np.inner(A,fpos))
     3825        rundata += 'bboxlist = [     # orthogonal coordinate for supercell corners\n'
     3826        for i in bbox:
     3827            rundata += '  '+str(list(i))+',\n'
     3828        rundata += ' ] # bboxlist\n\n'
     3829        atomlist,coordlist = MakefullrmcSupercell(Phase,RMCPdict)
     3830        rundata += 'atomlist = [  # [element, label, grouplist]\n'
     3831        for i in atomlist:
     3832            rundata += '  '+str(i)+',\n'
     3833        rundata += ' ] # atomlist\n\n'
     3834        rundata += 'coordlist = [     # (sym#, cell#, atom#, [ortho coords],)\n'
     3835        for i in coordlist:
     3836            rundata += '  '+str(i)+',\n'
     3837        rundata += ' ] # coordlist\n'
     3838    else:
     3839        rundata += "SymOpList = "+str([i.lower() for i in SymOpList]) + '\n'
     3840        rundata += 'atomList = ' + str(atomsList).replace('],','],\n  ') + '\n'
    37333841
    37343842    rundata += '\n# initialize engine\n'
     
    37373845projectStats = os.path.join(dirName, project + '.stats')
    37383846projectPlots = os.path.join(dirName, project + '.plots')
     3847projectXYZ = os.path.join(dirName, project + '.atoms')
    37393848pdbFile = os.path.join(dirName, project + '_restart.pdb')
    3740 # check Engine exists if so (and not FRESH_START) load it
    3741 # otherwise build it
     3849# check Engine exists if so (and not FRESH_START) load it otherwise build it
    37423850ENGINE = Engine(path=None)
    37433851if not ENGINE.is_engine(engineFileName) or FRESH_START:
    3744     ## create structure
    37453852    ENGINE = Engine(path=engineFileName, freshStart=True)
     3853'''
     3854    if RMCPdict.get('Groups',[]):
     3855        rundata += '''
     3856    # create structure from GSAS-II constructed supercell
     3857    bbox = (np.array(bboxlist[1::2])-np.array(bboxlist[0::2])).flatten()
     3858    pdb,grouplist = makepdb(atomlist,coordlist,bbox)
     3859    ENGINE.set_pdb(pdb)
     3860    ENGINE.set_boundary_conditions(bbox)
     3861    if grouplist: ENGINE.set_groups(grouplist)
     3862'''
     3863        if RMCPdict.get('GroupMode',0) == 0:   # 'Rotate & Translate'
     3864            rundata += '''
     3865    for g in ENGINE.groups:
     3866        TMG = TranslationGenerator(amplitude=0.2) # create translation generator
     3867        if len(g) > 1:  # create rotation generator for groups with more than 1 atom
     3868            RMG = RotationGenerator(amplitude=2)
     3869            MG  = MoveGeneratorCollector(collection=[TMG,RMG],randomize=True)
     3870        else:
     3871            MG  = MoveGeneratorCollector(collection=[TMG],randomize=True)
     3872        g.set_move_generator( MG )
     3873'''
     3874        elif RMCPdict.get('GroupMode',0) == 1: # 'Rotate only'
     3875            rundata += '''
     3876    for g in ENGINE.groups:
     3877        if len(g) > 1:  # create rotation generator for groups with more than 1 atom
     3878            RMG = RotationGenerator(amplitude=2)
     3879            g.set_move_generator( RMG )
     3880'''
     3881        else:                                  # 'Translate only'
     3882            rundata += '        # translate only set by default'
     3883    else:
     3884        rundata += '''
     3885    # create structure, let fullrmc construct supercell
    37463886    ENGINE.build_crystal_set_pdb(symOps     = SymOpList,
    37473887                                 atoms      = atomList,
    37483888                                 unitcellBC = cell,
    37493889                                 supercell  = supercell)
     3890    ENGINE.set_groups_as_atoms()
    37503891'''   
    3751     import atmdata
    3752     # rundata += '    # conversion factors (may be needed)\n'
    3753     # rundata += '    sumCiBi2 = 0.\n'
    3754     # for elem in Phase['General']['AtomTypes']:
    3755     #     rundata += '    Ci = ENGINE.numberOfAtomsPerElement["{}"]/len(ENGINE.allElements)\n'.format(elem)
    3756     #     rundata += '    sumCiBi2 += (Ci*{})**2\n'.format(atmdata.AtmBlens[elem+'_']['SL'][0])
    37573892    rundata += '    rho0 = len(ENGINE.allNames)/ENGINE.volume\n'
     3893    rundata += '\n    # "Constraints" (includes experimental data) setup\n'
    37583894    # settings that require a new Engine
    37593895    for File in Files:
     
    38023938            print('What is this?')
    38033939    minDists = ''
    3804     if BondList:
     3940    if BondList and RMCPdict.get('useBondConstraints',True):
    38053941        rundata += '''    B_CONSTRAINT   = BondConstraint()
    38063942    ENGINE.add_constraints(B_CONSTRAINT)
     
    38644000        c._constraint_copy_needs_lut = types.MethodType(_constraint_copy_needs_lut, c)
    38654001'''
    3866     rundata += '\n# set weights -- do this now so values can be changed without a restart\n'
     4002#    rundata += '\n# set weights -- do this now so values can be changed without a restart\n'
    38674003    # rundata += 'wtDict = {}\n'
    38684004    # for File in Files:
     
    38784014    #         typ = 'Struct'
    38794015    #     rundata += 'wtDict["{}-{}"] = {}\n'.format(typ,sfwt,filDat[1])
     4016    rundata += '\n# set PDF fitting range\n'
    38804017    rundata += 'for c in ENGINE.constraints:  # loop over predefined constraints\n'
    38814018    rundata += '    if type(c) is fPDF.PairDistributionConstraint:\n'
     
    39124049    rundata += 'steps = {}\n'.format(RMCPdict['Steps/cycle'])
    39134050    rundata += 'for _ in range({}):\n'.format(RMCPdict['Cycles'])
    3914     rundata += '    ENGINE.set_groups_as_atoms()\n'
    39154051    rundata += '    expected = ENGINE.generated+steps\n'
    39164052   
    39174053    rundata += '    ENGINE.run(restartPdb=pdbFile,numberOfSteps=steps, saveFrequency=steps)\n'
    39184054    rundata += '    writeCurrentStatus(ENGINE,statFP,projectPlots)\n'
    3919     rundata += '    if ENGINE.generated != expected: break # run was stopped\n'
    3920     rundata += 'statFP.close()\n'
    3921     rundata += 'print("ENGINE run time %.2f s"%(time.time()-time0))\n'
     4055    rundata += '    if ENGINE.generated != expected: break # run was stopped'
     4056    rundata += '''
     4057statFP.close()
     4058fp = open(projectXYZ,'w')  # save final atom positions
     4059fp.write('cell: {} {} {} {} {} {}\\n')
     4060fp.write('supercell: {} {} {}\\n')
     4061'''.format(*cell,*RMCPdict['SuperCell'])
     4062    rundata += '''# loop over atoms
     4063for n,e,(x,y,z) in zip(ENGINE.allNames,
     4064                       ENGINE.allElements,ENGINE.realCoordinates):
     4065    fp.write('{} {} {:.5f} {:.5f} {:.5f}\\n'.format(n,e,x,y,z))
     4066fp.close()
     4067print("ENGINE run time %.2f s"%(time.time()-time0))
     4068'''
    39224069    rfile = open(scrname,'w')
    39234070    rfile.writelines(rundata)
  • trunk/docs/source/packages.rst

    r5288 r5317  
    163163
    164164  **RMCProfile**
    165     Large-box PDF & S(Q) fitting. We have heard from users that V6.7.7
    166     of RMCProfile is compatible with the input created by GSAS-II,
    167     but not V6.7.9.
     165    Large-box PDF & S(Q) fitting. The GSAS-II interface was originally
     166    written for use with release 6.7.7 of RMCProfile, but updates have
     167    been made for compatible with 6.7.9 as well.
     168
     169    RMCProfile must be downloaded by the user from
     170    http://rmcprofile.org/Downloads or
     171    https://rmcprofile.pages.ornl.gov/nav_pages/download/
    168172
    169173  **fullrmc**
    170     A modern software toolkit for large-box PDF & S(Q) fitting. Use
    171     version 5.0 or later. The implementation for this is not
    172     completed.
     174    A modern software framework for large-box PDF & S(Q) fitting. Note
     175    that the GSAS-II implementation is not compatible with the last
     176    open-source version of fullrmc, but rather the version 5.0 must be
     177    used, which is distributed as a compiled versions for 64-bit
     178    Intel-compatible processors running Windows, Linux and MacOS from
     179    website
     180    https://github.com/bachiraoun/fullrmc/tree/master/standalones. GSAS-II
     181    will offer to install this software into the binary directory when the fullrmc
     182    option is selected on the Phase/RMC tab.
    173183
    174184  **Dysnomia**
     
    184194
    185195  For other platforms/Python versions, it is probably best to use a
    186   separate Python interpreter.
     196  separate Python interpreter. If GSAS-II is installed with the conda
     197  package manager (the usual installation practice), the GUI will
     198  offer the option to install PDFfit2 when the option is selected on
     199  the Phase/RMC tab.
    187200   
    188201Supported Platforms
  • trunk/help/gsasII-phase.html

    r5272 r5317  
    73637363(giving Sequential PDFfit2 results).</p>
    73647364
     7365<h4 style='margin-left:0.5in'><a name=fullrmc>fullrmc</h3>
     7366
     7367<p style='margin-left:0.75in'>The
     7368<span class=SpellE>fullrmc</span> program is a large-box pair distribution
     7369function modeling library developed by Bachir Aoun [Fullrmc,
     7370a Rigid Body Reverse Monte Carlo Modeling Package Enabled with Machine Learning
     7371and Artificial Intelligence&quot;, B. Aoun, <i>Jour. Comp. Chem.</i> <b>(2016)</b>,
     737237, 1102-1111. DOI: <a href="https://doi.org/10.1002/jcc.24304">10.1002/jcc.24304</a>].
     7373Extensive information about <span class=SpellE>fullrmc</span> is found,
     7374including <span class=GramE>a number of</span> explanatory videos, along with
     7375older source code on GitHub: <a
     7376href="https://bachiraoun.github.io/fullrmc/">https://bachiraoun.github.io/fullrmc/</a>. Note
     7377that the GSAS-II implementation is not compatible with the
     7378    open-source version of fullrmc, but rather the new version 5.0 must be
     7379    used, which is distributed as a compiled versions for 64-bit
     7380    Intel-compatible processors running Windows, Linux and MacOS from website
     7381<A href="https://github.com/bachiraoun/fullrmc/tree/master/standalones">
     7382https://github.com/bachiraoun/fullrmc/tree/master/standalones</A>.
     7383Note that an even newer and more powerful version of fullrmc is
     7384available for cloud computing by subscription at <A href="https://fullrmc.com">
     7385https://fullrmc.com</A>.
     7386When fullrmc is selected in this tab, GSAS-II use the
     7387GSAS-II <a href="#Preferences">configuration variable</a>
     7388<tt>fullrmc_exec</tt>, which if defined points to a Python image with
     7389fullrmc.  Otherwise GSAS-II will look in the
     7390following places, in the order specified, for a Python image for a
     7391file named <tt>fullrmc5*64bit</tt> (MacOS or Linux) or
     7392<tt>fullrmc5*.exe</tt> (Windows):
     7393<OL style='margin-left:0.75in'>
     7394  <LI>The location where GSAS-II is installed,
     7395  <LI>The location where Python is installed,
     7396  <LI>The location where the GSAS-II binaries are found,
     7397  <LI>the current default location
     7398  <LI>and all directories in the system path.
     7399</OL>
     7400
    73657401<h4 style='margin-left:.25in'><a name=Phase-ISODISTORT>ISODISTORT</a></h4>
    73667402
     
    74837519</span></div>
    74847520
    7485 <p class=MsoNormal><span style='mso-fareast-font-family:"Times New Roman"'><!-- hhmts start -->Last modified: Fri May  6 13:29:00 CDT 2022 <!-- hhmts end --><o:p></o:p></span></p>
     7521<p class=MsoNormal><span style='mso-fareast-font-family:"Times New Roman"'><!-- hhmts start -->Last modified: Wed Jul 27 15:05:57 CDT 2022 <!-- hhmts end --><o:p></o:p></span></p>
    74867522
    74877523</div>
  • trunk/help/gsasII.html

    r5275 r5317  
    97029702using Sphinx. </p>
    97039703
    9704 <h3 style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><a
    9705 name=fullrmc><strong><span style='mso-fareast-font-family:"Times New Roman"'>Access
    9706 to </span></strong></a><span class=SpellE><span style='mso-bookmark:fullrmc'><strong><span
    9707 style='mso-fareast-font-family:"Times New Roman"'>fullrmc</span></strong></span></span><span
    9708 style='mso-bookmark:fullrmc'><span style='mso-fareast-font-family:"Times New Roman"'><o:p></o:p></span></span></h3>
    9709 
    9710 <span style='mso-bookmark:fullrmc'></span>
    9711 
    9712 <p class=MsoNormal style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'>The
    9713 <span class=SpellE>fullrmc</span> program is a large-box pair distribution
    9714 function modeling library developed by Bachir Aoun [&quot;<span class=SpellE>Fullrmc</span>,
    9715 a Rigid Body Reverse Monte Carlo Modeling Package Enabled with Machine Learning
    9716 and Artificial Intelligence&quot;, B. Aoun, <i>Jour. Comp. Chem.</i> <b>(2016)</b>,
    9717 37, 1102-1111. DOI: <a href="https://doi.org/10.1002/jcc.24304">10.1002/jcc.24304</a>].
    9718 Extensive information about <span class=SpellE>fullrmc</span> is found,
    9719 including <span class=GramE>a number of</span> explanatory videos, along with
    9720 the source code on GitHub: <a href="https://bachiraoun.github.io/fullrmc/">https://bachiraoun.github.io/fullrmc/</a>.
    9721 Use of <span class=SpellE>fullrmc</span> requires a set of Python packages that
    9722 can be installed along with the packages needed for GSAS-II, but Windows and
    9723 MacOS users will likely find it easier to install a pre-compiled version of <span
    9724 class=SpellE>fullrmc</span> by downloading it <a
    9725 href="https://drive.google.com/drive/folders/10hxmQviKoMaW9R4MxsaiDyPSretxr_P7">from
    9726 here</a>. To locate a version of Python containing <span class=SpellE>fullrmc</span>,
    9727 the following locations are checked (in the order specified): </p>
    9728 
    9729 <p class=MsoListParagraphCxSpFirst style='text-indent:-.25in;mso-list:l40 level1 lfo44;
    9730 tab-stops:list .5in'><![if !supportLists]><span style='mso-list:Ignore'>1.<span
    9731 style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><![endif]>The
    9732 GSAS-II <a href="#Preferences">configuration variable</a> <span class=SpellE><tt><span
    9733 style='font-size:10.0pt'>fullrmc_exec</span></tt></span> can point to a Python
    9734 image. </p>
    9735 
    9736 <p class=MsoListParagraphCxSpMiddle style='text-indent:-.25in;mso-list:l40 level1 lfo44;
    9737 tab-stops:list .5in'><![if !supportLists]><span style='mso-list:Ignore'>2.<span
    9738 style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><![endif]>The
    9739 Python interpreter running GSAS-II is checked if <span class=SpellE>fullrmc</span>
    9740 can be imported </p>
    9741 
    9742 <p class=MsoListParagraphCxSpLast style='text-indent:-.25in;mso-list:l40 level1 lfo44;
    9743 tab-stops:list .5in'><![if !supportLists]><span style='mso-list:Ignore'>3.<span
    9744 style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><![endif]>The
    9745 location where GSAS-II is installed, the location where Python is installed,
    9746 the location where the GSAS-II binaries are found, the current default location
    9747 and all directories in the system path are all checked for a file named <tt><span
    9748 style='font-size:10.0pt'>&quot;<span class=SpellE>fullrmc</span>*macOS*i386-64bit&quot;</span></tt>
    9749 (MacOS), <tt><span style='font-size:10.0pt'>&quot;<span class=SpellE>fullrmc</span>*.exe&quot;</span></tt>
    9750 (Windows) or <tt><span style='font-size:10.0pt'>&quot;<span class=SpellE>fullrmc</span>*&quot;</span></tt>
    9751 (Linux). </p>
    9752 
    97539704<div class=MsoNormal align=center style='text-align:center;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
    97549705style='mso-no-proof:yes'>
     
    97659716</span></div>
    97669717
    9767 <p class=MsoNormal style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><!-- hhmts start -->Last modified: Fri May 13 16:26:04 CDT 2022 <!-- hhmts end --></div>
     9718<p class=MsoNormal style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><!-- hhmts start -->Last modified: Wed Jul 27 14:40:38 CDT 2022 <!-- hhmts end --></div>
    97689719
    97699720</body>
Note: See TracChangeset for help on using the changeset viewer.