A custom fitting equation that also calls a fit

Hi everyone,

I have written a fitting function to do some complicated fitting for me. to calculate a y value for given parameters my fit function runs a simulation of a differential equation to find out how a variable changes with time, and then fits this response to an exponential to find out the decaying time scale. for this exp fit fit I use a custom coefficients wave so to not interfere with the coefficient wave of the main fit. I still see problems, mainly:

1) My main fit freezes after awhile (I have to ctrl-alt-delete to exit), and at this time I see that it begins to think there are three coefficients instead of two that I expect. I wonder if somehow the exp fitting (which has three fit parameters) that happens during the fit some how messes with the fit.
2) I see the fitting algorithm run the same parameters (or very close to the same) a couple times in a row before moving on to the next point, this seems strange and adds significant time to my fit, maybe this is normal?

I know igor uses a lot of other variables during a fit, maybe I need to somehow save the current values before running my exp fit and then reload the values back in? If this is the case are there particular values which are important?

Michael
The response is not correct, unfortunately. The response dealt with using FindRoots in a fitting function. Unfortunately, Igor's curve fitting operations are not written in a re-entrant way, so you can't use a curve fit inside a fit.

I recently added a check for recursion in the fitting code so that instead of crashing it would issue an error. What version of Igor are you using?

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
I am using version 6.2.2.2, downloaded recently. It doesn't give any warning messages. I feared that this was the case.

Any work arounds I could do?
SailBlue5 wrote:
I am using version 6.2.2.2, downloaded recently. It doesn't give any warning messages. I feared that this was the case.

Hm. I just checked our source code repository- I added that error message three years ago. Seems like just yesterday... You didn't show the code of your fit function, so it's hard to know what might be going wrong there. Possibly you need to use the special variable V_FitError. To read about it, execute this command:

DisplayHelpTopic "Special Variables for Curve Fitting"
Quote:
Any work arounds I could do?

Well, come to think of it, you might be able to do it by spawning a separate thread and doing your inner curve fit in that thread. Your inner fit function will have to be thread-safe. It's not the usual reason for threading (that would be speed, and since your outer fit requires the result from your inner thread, they can't run concurrently and won't save time). But a thread has its own environment, including global variables so it should solve the re-entrancy problem.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
#pragma rtGlobals=1 // Use modern global access method.

//This function works as a basic fit function for Diffusion's dependence on oscillating amplitude
Function DiffusionVsOscAmplitude(w,OscAmp) : FitFunc
    Wave w
    Variable OscAmp

    //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    //CurveFitDialog/ Equation:
    //CurveFitDialog/ This runs a simulation to the differential equation determine the fit.
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 1
    //CurveFitDialog/ OscAmp
    //CurveFitDialog/ Coefficients 2
    //CurveFitDialog/ w[0] = Ds
    //CurveFitDialog/ w[1] = invtm
print "Starting fitfunc"

    //Set global variables
    variable /G position_cm = 200e-7
    variable /G SimLength_cm =400e-7
    Variable /G dx_cm = 2e-7
    variable /G dt_s = .0002
    variable /G SimTime_s = 3
   
    //Make the sensitive volume
    SenSliceFull(OscAmp)
    print OscAmp
    print w[0]
    print w[1]
print "Calling runSim" 
    return RunSimulation(w[0],w[1])
End


//To run the simulation
Function RunSimulation(Ds, invtm)
    Variable Ds     //diffusion constant
    Variable invtm  //Relaxation rate for T_1 or \tau_m
print "In RunSim"
    variable /G position_cm
    variable /G SimLength_cm
    Variable /G dx_cm
    variable /G dt_s
    variable /G SimTime_s
    Wave ExpFits
    Wave SenSlice
    Wave Spins
   
    variable Iterations = round(SimTime_s/dt_s) //Number of spatial points to simulate
    variable Positions = round(SimLength_cm/dx_cm)  //Number of time steps to take
    variable frac = cosh(dt_s*invtm)*exp(-1*dt_s*invtm)  //the fraction of spins that flip in time dt.
    variable i  //Will hold the time step
    variable j //will hold the position step
    variable k //used to update plots every now and then
    variable sum  //will hold the integration of Spin*SenSlice
    variable result  //The resultant measured inverse corrolation time of the force
   
    Make /O /N=(Positions) TempSpins  //This will hold the spin state at the next time step temporarly
    Make /O /N=(Iterations) OrigSpinState  //This will hold how much of the original spin state is left convolved with the sen slice vs time (for each dt)
    SetScale/P x 0,(dt_s),"", OrigSpinState  //each point repersents a single time step
    Make /O /N=2 TempCoef  //Since we will have a fit inside a fit we need to do house cleaning so the two W-coef waves do not screw with each other
   
    OrigSpinState = nan  //just so I don't have lingering values from a previous run
    for(i=0;i<Iterations;i=i+1)
        sum = 0
        for(j=0;j<Positions; j=j+1)
            sum = sum + SenSlice[j]*Spins[j]  //Integrate to find "force"
           
            //Spins diffusing
            if(j==0)
                TempSpins[j] = Spins[j] + Ds*dt_s*(Spins[j+1]-Spins[j])/(dx_cm*dx_cm)   //spins are blocked from diffusing past on the left side
                //TempSpins[j] = 0                                                  //Spins diffuse past the left side (and disapear)  
            elseif(j==Positions-1)
                TempSpins[j] = Spins[j] + Ds*dt_s*(Spins[j-1]-Spins[j])/(dx_cm*dx_cm)  //spins are blocked from diffusing past on the right side
                //TempSpins[j] = 0                                                  //Spins diffuse past the right side (and disapear)
            else
                TempSpins[j] = Spins[j] + Ds*dt_s*(Spins[j-1]+Spins[j+1]-2*Spins[j])/(dx_cm*dx_cm)  
            endif
        endfor
       
        OrigSpinState[i] = sum  //The "force" at this time period
       
        for(j=0;j<Positions; j=j+1)
            Spins[j] = frac*TempSpins[j]  //Get ready for next iteration
        endfor
        if(k<1)
            doUpdate
            k=Iterations/100
        endif
        k=k-1
    endfor
    print "Calling fit"
    CurveFit/NTHR=0 exp kwCWave=ExpFits,  OrigSpinState /D
    print ExpFits[2]
    print "Returning"
    return ExpFits[2]
end

Function SenSliceFull(OscAmp)
    variable OscAmp
    variable /G position_cm
    variable /G SimLength_cm
    Variable /G dx_cm
   
    variable i
   
    Make /O /N=(round(SimLength_cm/dx_cm)) SenSlice
    Make /O /N=(round(SimLength_cm/dx_cm)) Spins
    for(i=0;i<round(SimLength_cm/dx_cm);i=i+1)
        SenSlice[i]=0
        Spins[i]=0
    endfor
    for(i=ceil(-1*(OscAmp/dx_cm));i<=floor(OscAmp/dx_cm);i=i+1)
        SenSlice[round(position_cm/dx_cm)+i]=Cos((i*dx_cm/OscAmp)*(pi/2))
        Spins[round(position_cm/dx_cm)+i]=1
    endfor
    SetScale/P x 0,(dx_cm),"", SenSlice
    SetScale/P x 0,(dx_cm),"", Spins
end


There is my code. The fit is being done in the function run simulation right before the return. I'll look in to threading and the special variable. Thanks.

Michael
Michael-

Here is some code that might serve as a start on trying my idea. To read about threading, and what the calls in this code do, execute this command:

DisplayHelpTopic "ThreadSafe Functions and Multitasking"

Note that my code is not complete, so I haven't tested it. But it should serve as a starting point. I will be very interested to know if this works!

threadsafe Function DoMyFit(cwave, datawave)
    Wave cwave, datawave
   
    CurveFit/NTHR=1 exp kwCWave=cwave,  datawave
end

Function runsimulation(Ds, invtm)
    Variable Ds     //diffusion constant
    Variable invtm  //Relaxation rate for T_1 or \tau_m
   
    //*** lots of code here****
   
    Variable threadid = ThreadGroupCreate(1)        // just one thread to encapsulate the inner fit
    ThreadStart threadid, 0, DoMyFit(ExpFits,  OrigSpinState)
    do
        variable tgs= ThreadGroupWait(threadid,5000)        // five-second wait is excessive, but we don't want to spin the loop.
                                                // We just want to wait until the inner fit is done, which could be fairly lengthy.
    while( tgs != 0 )

    return ExpFits[2]
end


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
johnweeks wrote:
Michael-

Here is some code that might serve as a start on trying my idea. To read about threading, and what the calls in this code do, execute this command:

DisplayHelpTopic "ThreadSafe Functions and Multitasking"

Note that my code is not complete, so I haven't tested it. But it should serve as a starting point. I will be very interested to know if this works!

threadsafe Function DoMyFit(cwave, datawave)
    Wave cwave, datawave
   
    CurveFit/NTHR=1 exp kwCWave=cwave,  datawave
end

Function runsimulation(Ds, invtm)
    Variable Ds     //diffusion constant
    Variable invtm  //Relaxation rate for T_1 or \tau_m
   
    //*** lots of code here****
   
    Variable threadid = ThreadGroupCreate(1)        // just one thread to encapsulate the inner fit
    ThreadStart threadid, 0, DoMyFit(ExpFits,  OrigSpinState)
    do
        variable tgs= ThreadGroupWait(threadid,5000)        // five-second wait is excessive, but we don't want to spin the loop.
                                                // We just want to wait until the inner fit is done, which could be fairly lengthy.
    while( tgs != 0 )

    return ExpFits[2]
end


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com



Creating a new thread worked. I was able to perform the fitting function within a fitting function.

SailBlue5 wrote:
Creating a new thread worked. I was able to perform the fitting function within a fitting function.

Excellent! Thanks for letting me know. There may be others that could benefit from this.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com