Question about "Fitting Sums of Fit Functions" (FuncFit)

I would like to fit a spectrum with a sum of several waves. Until the actual fit, I can also read in different numbers of waves and pass them on to the actual user function that is to perform the fit.
For this I would actually pass the fit as a string to the FuncFit, but unfortunately I don't quite understand the requirements that the string must fulfil in the end.
If I were to display this fit normally, it would look like this, for example:

Threadsafe function f_fit_function_name(w,x) : FitFunc
    Wave w
    Variable x
    wave wave0=path
    wave wave1=path
    return w[0]*wave0(x)+w[1]*wave1(x)+w[2]
End

And be called using this function:

FuncFit/Q f_fit_function_name wave[v_start,v_end] /D /C={M_FitConstraint,W_FitConstraint}

If I have understood correctly, I can also trigger such a function via a string:

FuncFit/Q {string=fitSpecStr} wave[v_start,v_end] /D /C={M_FitConstraint,W_FitConstraint}

There is something about it in this chapter in the manual:

DisplayHelpTopic "FuncFit" //Fitting Sums of Fit Functions

The function could be represented like this:

{{func1, coef1, keyword =value },{func2, coef2, keyword =value }, ...}

Or the expression can be entered via a string:

{string = fitSpecStr}
with fitSpecStr = "{func1, coef1, keyword =value },{func2, coef2, keyword =value }, ..."

But I'm not really getting anywhere here. I can leave out the keywords, but the comma has to stay? Or does the statement apply to all other commas?

"{wave0, w[0],},{wave1, w[1],},{wave2, w[2],}"
or
"{wave0, w[0]},{wave1, w[1]},{wave2, w[2]}"

Can "func" be a wave? Or do I have to define the wave as a wave?

"{wave wave0, w[0]},{wave wave1, w[1]},{wave wave2, w[2]}"

Do I have to specify the x-dependency?

"{wave0(x), w[0]},{wave1(x), w[1]},{wave2(x), w[2]}"

Is coef the same as w[n] or is it something like W_coef[n]?

"{wave0(x), W_Coef[0]},{wave1(x), W_Coef[1]},{wave2(x), W_Coef[2]}"

How can I represent an offset as a function? Simply a "1"?

"{wave0(x), W_Coef[0]},{wave1(x), W_Coef[1]},{1, W_Coef[2]}"

I have tried various things, but always get the same error:

error: expected fitting function

And directly another question: Is a FuncFit based on a string Threadsafe?

I know the questions are very specific, but still hope someone can help me.

Can you save a global wave reference wave filled with references to the waves to be fit?

Then you invoke the fit function with an appropriately dimensioned coefficient wave, the fit function looks up the wave reference wave, and loops though the waves adding together values at x, each multiplied by a fit coefficient.

 

So you mean a multidimensional reference wave where each column contains one reference wave?

Threadsafe function f_fit_function_name(w,x) : FitFunc
    Wave w
    Variable x
    wave reference=path
    variable index
    string s_return
    for (index=0;index<(dimsize(reference,1));index+=1)
        s_return+="w["+num2str(index)+"]*reference[x]["+num2str(index)+"]+"
    endfor
    s_return+="w["+num2str(index)+"]"
    return $s_return
End

That would be a good solution, but how do I assemble a return in this case? I can't set the loop around a return, isn't is? (The frist return of the loop will end the function.) Igor doesn't want to translate a string like in my example. Probably this problem is super simple, but in the DisplayHelpTopic "return" I could not find anything about the form in which the expression has to be passed. Any idea?

Thanks!

i mean something like this

function fitFunc(wave w_coef, variable x)
    wave /WAVE refs = pathToWaveRefsWave
    variable i
    variable total = w_coef[numpnts(w_coef)-1]
    for(i=numpnts(refs);i>=0;i--)
        wave w = refs[i]
        total += w_coef[i] * w(x)
    endfor
    return total
end

see  also

DisplayHelpTopic "Wave Reference Waves"

Note: I understood from your question that you want to perform a fit like the one in the first function in your post, but with an arbitrary selection of waves rather than wave0 and wave1. Maybe that wasn't what you meant?

So there was my error of thought. Then I will implement it with this much simpler solution. Thank you!

Back from vacation...

I will note that the Sum of Fit Functions facility is for a different purpose. It was created originally with Multipeak Fit in mind; each of the summed fit functions represents a single peak or a background function. The string is used to list all the fit functions and coefficient waves required.

If you wanted to make your life very complicated, you could write a fit function that computes the multiplier for one of your reference waves, and then use the sum of fit functions feature to add them together. But that would be difficult to set up, and probably much slower. The WAVE wave is a much better solution.

I am attaching this question in this thread because it is thematically related to it:
Is there a way to create a comparable dynamic function for an all-at-once function?
According to the manual, a-a-o functions cannot be created or edited within the Curve Fitting dialog. But can they be created within a FuncFit function?
At my first attempts I get the error that the variable must not contain a complete wave. I am now unsure if I am trying something here that cannot work at all.

Threadsafe function f_fitFunc_lc_MT_new(pw,yw,xw) : FitFunc
    Wave pw,yw,xw
    wave /WAVE list=root:listwave
    variable index
    variable v_return=0
    for (index=0;index<(dimsize(list,0));index++)
        wave w=list[index]
        //next line: error "ambiguous wave point number" for "w"
        v_return+=pw[index]*w
    endfor
    v_return+=pw[(dimsize(list,0))]
    yw = v_return
end

The idea here is that it will end up working like this function:

Function f_myFitFunc(pw, yw, xw) : FitFunc
   wave pw, yw, xw
   wave w1=root:wave0
   yw = pw[0]*w1 + ... + pw[n]
End

To me, this looks like an actually similar result when comparing normal fit functions with a-a-o fit funcitions (the end result now says "yw =" instead of "return"). But that is perhaps too simple a thought.

Edit: Wouldn't it be possible to make the execute command compatible with FuncFits in a future Igor (sub)version?

Function f_myFitFunc(pw, yw, xw) : FitFunc
   wave pw, yw, xw
   wave w1=root:wave0
   string s_execute="yw = pw[0]*wave0+pw[1]"
   execute s_execute
end

That would make such dynamic problems easier, perhaps?

I am not sure what you are trying to do, but your first example contains a few things which cannot work (at least in this way):

v_return+=pw[index]*w

You are trying to assign a whole wave to a variable, which does not make sense. You need to specify the point of the wave which you like to assign such as w[0]. Next:

yw = v_return

You are assigning the variable to your output wave, which makes all points of the wave the same. I don't think this is what you want (unless you want a horizontal line). An all-at-once fitting function writes the result of some calculation into the wave (as the name says) all-at-once, so ideally you want to give a resulting value to each point of yw. Also, you are not using xw at all, which does not seem right (how is the x-axis involved in your calculation).

For a point-by-point func fit, you can create what is fitted with return using a variable. This was the solution of tony, which works well. In which form would it have to be passed for an all-in-ones fit function? I think this point is my biggest problem: I have no idea. Of course, it may be that this easy solution works for a normal FuncFit, but not for an all-at-ones.

(I would prefer a way via a string, but that doesn't work, I think.)

It seems that the xw has to come in brackets after each wave:

Function f_myFitFunc(pw, yw, xw) : FitFunc
   wave pw, yw, xw
   wave w1=root:wave0
   ...
   yw = pw[0]*w1(xw) + ... + pw[n]
End

In reply to by ggermer

function f_fitFunc_lc_MT_new(pw,yw,xw) : FitFunc
    Wave pw,yw,xw
    wave /WAVE list=root:listwave
    variable index

    for (index=0;index<(dimsize(list,0));index++)
        wave w=list[index]
        yw+=pw[index]*w
    endfor
end

Edit: I think it's okay to ignore xw if you know that points in each of listwaves correspond to points in yw.

Unless you need an all-in-one fit, probably better to stick with the normal fitting function.

In reply to by tony

if you want to fit subranges you will need something like this:

function AllAtOnce(wave pw, wave yw, wave xw) : FitFunc
    wave /WAVE list=root:listwave
    int index, imax
    imax = dimsize(list,0)
    for (index=0;index<imax;index++)
        wave w = list[index]
        yw += pw[index] * w(xw[p])
    endfor
end

 

Thank you very much, I will try that.
What are the disadvantages of an all-in-one fit compared to a normal fit? I was hoping to save time while keeping the quality of the coefficients the same.

Yes, an all-at-once fit function is faster if you are fitting many points because all the model values are computed with one call to your fitting function. But the standard fit function that returns one model value for one value of the independent variable is much easier to use outside of curve fitting because you can simply assign the result to a variable or to a wave with a standard wave assignment. With the AAO style function, you MUST create an X wave to pass to the function even if your values are evenly spaced in X.

You have probably figured out that in an AAO function, the return value is irrelevant. All the action happens in an assignment to the YW wave.

Adding quite a lot of complexity that may or may not be justified: another approach would be a structure fit function. The standard parts of the fit function are encapsulated at the top of a structure, and then you can add arbitrary items to the structure. Such items might include a reference to the WAVE wave containing your list of waves, and maybe information on a subset of that list if that might be useful. The BIG downside is that you can't create a stand-alone structure in Igor, so you have to write a wrapper function that creates the structure and then invokes FuncFit.

Seeing all these lists of waves and arbitrary numbers of coefficients required to fit the arbitrary sums compels me to give a warning:

You MUST use ALL the coefficients in your fit expression. Any unused points in your coefficient wave will result in a zero derivative and a guaranteed Singular Matrix error. So you will have to make sure the coefficient wave and the number of terms you want to sum always agree with each other. One way to do that is to write a wrapper function that sets up the required conditions. Now a structure fit function is sounding more appealing...

Thank you for the explanation.

I know the problems with the errors for FitFunctions with a wrong number of input parameters. Therefore, I have an input window that makes sure that the appropriate length of the waves is generated before the fits. (And a function that converts limit inputs to matrix format.)

Tony's solution seems to be compatible with minor changes, fortunately, so the AAO fit works and save time (factor 3). Many thanks again at this point! So I hope I don't need the structures, but will look at them.