Anme
Anme

Reputation: 35

Allow x to shift during linear combination fitting

I have three sets of data (x,y) that define unique lineshapes. Using linear combination fitting I want to fit these three lineshapes to a fourth. I can set up the simple code below:

#read in data (three components)
header_list=['Energy','Intensity']

component_1 = pd.read_csv('Lineshape_average.txt', delimiter="\t", skiprows=1,names=header_list)
component_2=pd.read_csv('Morb_11.txt', delimiter="\t",skiprows=1,names=header_list)
component_3=pd.read_csv('PM224.txt', delimiter="\t", skiprows=1,names=header_list)

c1=component_1['Intensity']
c2=component_2['Intensity']
c3=component_3['Intensity']

#read in data to be fit
df1 = pd.read_csv(file_name, delimiter="\t", skiprows=1,names=header_list)
df1['unc']=0.1

#set up model
def equation(params, obvs_intensity, uncertainty):
    a = params['a']
    b = params['b']
    c = params['c']

    calc_intensity=a*c1+b*c2+c*c3

    return (obvs_intensity-calc_intensity)/uncertainty

params = Parameters()
params.add('a', value = 0.33,min=0, max=1)
params.add('b',value =0.33,min=0, max=1)
params.add('c', value = 0.33, min=0, max=1)

#run model
result = minimize(equation, params, args =(df1['Intensity'],df1['unc']), nan_policy='omit')

Is there a way to allow the three components to shift in x (energy) so that I can get a better fit?

Upvotes: 0

Views: 32

Answers (1)

deep-learnt-nerd
deep-learnt-nerd

Reputation: 189

You could try to fit your data using linear interpolation. You can for instance use scipy.interpolate.interp1d.

from scipy.interpolate import interp1d

f_intensity_1 = interp1d(component_1["Energy"], component_1["Intensity"])
f_intensity_2 = interp1d(component_2["Energy"], component_2["Intensity"])
f_intensity_3 = interp1d(component_3["Energy"], component_3["Intensity"])

f_intensity_df = interp1d(df["Energy"], df["Intensity"])
f_uncertainty_df = interp1d(df["Energy"], df["unc"]) # this probably will be constant in your case

Then you can add the energy as a parameter:

params = Parameters()
params.add('a', value = 0.33,min=0, max=1)
params.add('b',value =0.33,min=0, max=1)
params.add('c', value = 0.33, min=0, max=1)

# You can improve that using your knowledge of the system
params.add('e', value=component_1["Energy"].mean(), min=component_1["Energy"].min(), max=component_1["Energy"].max()) 

And update your equation as

def equation(params):
    a = params['a']
    b = params['b']
    c = params['c']
    e = params['e']

    c1 = f_intensity_1(e)
    c2 = f_intensity_2(e)
    c3 = f_intensity_3(e)

    obs_intensity = f_intensity_df(e)
    uncertainty = f_uncertainty_df(e)

    calc_intensity=a*c1+b*c2+c*c3

    return (obvs_intensity-calc_intensity)/uncertainty

Would something like that work for you?

Upvotes: 0

Related Questions