Python script with autofitting functionsΒΆ

import os,time,shutil
import subprocess
import numpy as np
import pandas as pd
def addinitmacline(macline,templateinitfile,initfile):

    f=open(templateinitfile)
    lines=f.readlines()
    f.close()
    
    if os.path.isfile(initfile):
            os.remove(initfile)
    
    f=open(initfile,"w")
    for line in lines:
        if line.endswith('\n'):
            f.write(line)
        else:
            f.write(f"{line}\n")
    if lines[-1]!=macline:
        f.write(macline)
    f.close()

def runrod(rodexe):
    return subprocess.Popen(rodexe,cwd=os.path.dirname(rodexe),creationflags=subprocess.CREATE_NEW_CONSOLE) 

def checkchidiff(fitlist):
    return fitlist.values[2:].max()-fitlist.values[2:].min()

def domacrofits(donefile,rodexe):
    if os.path.isfile(donefile):
        os.remove(donefile)
    rodproc=runrod(rodexe)
    while not os.path.isfile(donefile):
        time.sleep(5)
    rodproc.kill()
    
def calcfitlist(run,n):
    ranges=[]
    for i in np.arange(0,n):
        #print(i)
        #parse information from .par file for fitting cycle
        fitdf=pd.read_csv('{}_{}.par'.format(run,str(i+1)),header=0)
        
        if i==1:
            fitted=[]
            for n in np.arange(len(fitdf)):
                if ('YES' in fitdf.iloc[n][0]):
                   # print(i)
                    #print('par {}: {}'.format(str(n-3),fitdf.iloc[n][0]))
                    fitted.append(n-4)
                    ranges.append('par {}: {}'.format(str(n-3),fitdf.iloc[n][0]))

        #parse location of dataset file
        datfile=fitdf.iloc[0][0].split(' ')[2]

        #read in dataset from file
        dat=pd.read_csv(r'{}'.format(datfile),sep='\s+')

        #calculate the number of datapoints
        ndat=len(dat)

        #calculate the number of free parameters used in the fitting
        nfree=len(fitdf[fitdf['!results_from_loop_{}'.format(i+1)].str.contains('YES')])

        #get non-normalised chi^2 value
        chi2=float(fitdf.iloc[1][0].split('=')[1])

        #calculate normalised chi^2 value following equation from ROD source code
        normchi2=round(chi2/(ndat-nfree+1e-10),4)

        #save normalised chi^2 value as panda series and add to total list
        fitval=pd.Series(normchi2,index=['fit{}'.format(i)])
        if i==0:
            fitlist=fitval
        else:
            fitlist=pd.concat([fitlist,fitval])
    return fitlist,fitted,ranges,fitdf 



def createmacro(mname,files,startvals,donefile,fittype):
    mactypes={'ASA':'fitlogloop5','RUN':'fitlogloop5run'}
    f=open(fr"{files['fitmac']}",'w')
    f.write(fr"re bul {files['bul']}"+'\n')
    f.write(fr"re dat  {files['dat']}"+'\n')
    f.write('mac sfsetup'+'\n')
    f.write(fr"mac {files['loadmac']} return return"+'\n')
    outname=mname.replace('.sur','')
    f.write(fr"re fit {files['fit']}"+'\n')
    f.write(fr"re par {startvals}"+'\n')
    f.write(f'mac {mactypes[fittype]}'+'\n')
    f.write(fr"li par {donefile} done")
    f.close()
    

def fitloop(modname,fitlist,files,fit5path,donefile,rodexe,count,run,fittype):
    while checkchidiff(fitlist)>0.01:
        startvals=fit5path
        createmacro(modname,files,startvals,donefile,fittype)
        domacrofits(donefile,rodexe)
        count+=1
        print(f'{fittype} loop {count}')
        fitlist,fitted,ranges,fitdf=calcfitlist(run,5)
    return fitlist[4],count