Define variable(s) for Funcfit

For a non-linear least square fitting, I made a script as follows. Here, the governing equation is FF_mag * magsqr(FF_uc*FF_ctr + FF_duc + FF_ads + FF_adw + FF_lw).
Each FF_* has variable x. Should I define FF_* as a variable or a wave?

Function Fitting_Engine(p,x)
    wave p
    variable x
   
    nvar ci
    nvar uc_occ_Y, uc_occ_Zr,  uc_occ_O, ci, u_Y, u_Zr, u_O
    wave ASF_Y, ASF_Zr, ASF_O, uc_position_Y, uc_position_Zr, uc_position_O

// ATOMIC POSITION //

// PERFECT UNIT CELL //
    variable/c FF_uc, FF_uc_Y, FF_uc_Zr, FF_uc_O, FF_ctr
       
    FF_uc_Y = atomic_frac_Y * ASF_Y * uc_occ_Zr * exp(ci*x*(temp_first_Y_position))*exp(-0.5*(x*u_Y)^2)
    FF_uc_Zr = atomic_frac_Zr * ASF_Zr * uc_occ_Zr * exp(ci*x*(temp_first_Zr_position))*exp(-0.5*(x*u_Zr)^2)
    FF_uc_O = 2*atomic_frac_O * ASF_O * uc_occ_O * exp(ci*x*(temp_first_O_position))*exp(-0.5*(x*u_O)^2)
   
    FF_uc = FF_uc_Y + FF_uc_Zr + FF_uc_O   
    FF_ctr = 1 / (1-exp(-ci*x*c))

// DISTORTED UNIT CELLS //
    variable i_F_duc
    variable/c FF_duc_Y, FF_duc_Zr, FF_duc_O, FF_duc   
    wave duc_occ_O
   
    FF_duc_Y = 0
    FF_duc_Zr = 0
    FF_duc_O = 0
   
    for (i_F_duc=0;i_F_duc<numpnts(temp_duc_position_O_reset);i_F_duc+=1)
        FF_duc_Y += atomic_frac_Y * ASF_Y* p[i_F_duc] * exp(ci*x*temp_duc_position_Y_reset[i_F_duc])*exp(-0.5*(x*u_Y)^2)
        FF_duc_Zr += atomic_frac_Zr *ASF_Zr * p[i_F_duc] * exp(ci*x*temp_duc_position_Zr_reset[i_F_duc])*exp(-0.5*(x*u_Zr)^2)
        FF_duc_O += 2*atomic_frac_O *ASF_O * duc_occ_O[i_F_duc] * exp(ci*x*temp_duc_position_O_reset[i_F_duc])*exp(-0.5*(x*u_O)^2)
    endfor

    FF_duc = FF_duc_Y + FF_duc_Zr + FF_duc_O
   

// INTERFACIAL MOLECULES //    
    variable/c FF_ads1, FF_ads2, FF_ads3, FF_ads
    nvar d_spacing_water

    FF_ads1 = ASF_Y*p[8]*exp(ci*x*(p[9]))*exp(-0.5*(x*p[10])^2)
    FF_ads2 = ASF_Y*p[11]*exp(ci*x*(p[12]))*exp(-0.5*(x*p[13])^2)
    FF_ads3 = ASF_Y*p[14]*exp(ci*x*(p[15]))*exp(-0.5*(x*p[16])^2)

    FF_ads = FF_ads1 + FF_ads2 + FF_ads3
   
    variable/c FF_adw1, FF_adw2, FF_adw, FF_lw
    wave ASF_H2O

    FF_adw1 = ASF_H2O * p[17] * exp(ci*x*(p[18]))*exp(-0.5*(x*p[19])^2)
    FF_adw2 = ASF_H2O * p[20] * exp(ci*x*(p[21]))*exp(-0.5*(x*p[22])^2)
    FF_adw = FF_adw1 + FF_adw2
    FF_lw = (ASF_H2O * exp(ci*x*p[23]) * exp(-0.5*(x*p[24])^2)) / (1-exp(-0.5*(x*p[25])^2)*exp(ci*x*d_spacing_water))

// MAGNIFICATION FACTORS //
    variable FF_mag, FT_Cell, FSpecular, FB
    nvar cell_water_thickness, photon_wavelength, attenuation_length, r_e, suc_area
   
    FT_cell = exp((-8*pi*cell_water_thickness)/(x*photon_wavelength*attenuation_length))
    FB = (1-p[26])^2/(1+p[26]^2-2*p[26]*cos(x*c))
    FSpecular = (4*pi*r_e/(x*suc_area))^2

    FF_mag = p[27] * FB * FT_Cell * FSpecular
   
    return FF_mag * magsqr(FF_uc*FF_ctr + FF_duc + FF_ads + FF_adw + FF_lw)
End
As near as I can tell, your two blocks of calculations for atomic positions are constant. They do not depend on p (the coefficient wave). You should calculate them entirely outside the fitting equation. This would define them as global waves dependent on x. They would be referenced inside the fitting equation by wave FF_uc, FF_ctr, FF_duc ...

Also, I cannot see where you are using certain values of p, for example p = 0 to 7. Why is this? And, with so many fitting coefficients, you might help make the code more readable by using a variable block at the start, for example as this ...

variable ads_f1 = p[8]
...
variable FF_mag_f = p[27]


Also, certain values that you define as globals via nvar would perhaps be better defined as static constants at the top of the procedure, for example ..

Static Constant ci = 3.14159
Static Constant uc_occ_Zr = ...


--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
In most applications your primary goal would be to make the fitting function as efficient as possible. If you rewrote your code using waves for FF_* you would more than likely make it less efficient because it takes time to lookup a wave. However, I think you have some problems with the code that may explain your question:

Your code would not compile. For example:
    FF_uc_O = 2*atomic_frac_O * ASF_O * uc_occ_O * exp(ci*x*(temp_first_O_position))*exp(-0.5*(x*u_O)^2)


Here the left hand side is a variable while on the right hand side you have ASF_O which is declared as a wave. You either need to have a wave expression, i.e., a wave on both sides of the expression or you need to use one point of the wave(s) on the right hand side. You need to address this issue before going any further.

Other comments:

If you are looking for efficiencies, consider removing every expression that does not depend on the fitting process and accessing it as either a constant or global. It may make your code less readable but it could pay off in execution time. For example, -8*pi*cell_water_thickness, photon_wavelength*attenuation_length and 4*pi*r_e/suc_area^2 do not appear to be evaluated in the fit so they should be computed outside and accessed as a single global. Similarly, d_spacing_water exists only as a product with ci so there is no reason to compute it each time.

Looking at your loop, you should probably replace numpnts(temp_duc_position_O_reset) with a variable evaluated once above the loop. Also, I don't see any declaration for the wave temp_duc_position_O_reset. Now depending on the size of NN=numpnts(temp_duc_position_O_reset) you could replace the loop with MatrixOP. I have a feeling though that NN is not large so in this case it is probably not worth the trouble.

I hope this helps,

A.G.
WaveMetrics, Inc.

Igor wrote:

If you rewrote your code using waves for FF_* you would more than likely make it less efficient because it takes time to lookup a wave.


AG ... Quick question on this. Suppose I have to use a predefined wave in this way ...

make/N=100 wsin = sin(p)

Function SomeFitFunc(ww,pnt)
    wave ww
    variable pnt

    wave wsin

   return (ww[0]*wsin[pnt] + ww[1]*pnt) // this is just some dummy calculation to show the concept
end


IOW, suppose I want to use a wave that I am able to pre-define external to the fit function and want to reference as a "lookup" inside the fit function itself. What is the most effective way to do this?

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
Jeff-

Since you like complicated solutions... :)

Look into a Structure Fit Function (DisplayHelpTopic "Structure Fit Functions"). You can add a wave to the structure that gets passed to the fit function, which means you don't have to look it up inside the function. But it requires that you use a driver function to set up the structure and call FuncFit.

Otherwise, there is no way to get around the WAVE lookup. Use an all-at-once function to minimize the number of times the fit function gets called, and consequently, the number of times the wave has to be looked up. Make sure you have few (or no!) other waves in the current data folder.

Function SomeFitFunc(ww,p)

I hate to be pedantic, but it's really terrible to call an input variable "p". I know, it's almost as bad to call it "x", which we do numerous times in the documentation. We live and learn. And the OP had p for the coefficient wave. He will also learn this now :)

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

Since you like complicated solutions... :)



I'm just playing devil's advocate from the point where AG prompted the inquiry by his open-ended comment.

I appreciate the clarification if for no other reason than logging an easy reference point of the information in case anyone else has a similar question.

johnweeks wrote:


Function SomeFitFunc(ww,p)

I hate to be pedantic, but it's really terrible to call an input variable "p". ...


The insight is appreciated. That was my "quick and dirty" posting. Normally, I avoid such mistakes in my code.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
jjweimer wrote:
The insight is appreciated. That was my "quick and dirty" posting. Normally, I avoid such mistakes in my code.

I know that; we've known you for a very long time! But I couldn't let it go in a public forum...

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
johnweeks wrote:
jjweimer wrote:
The insight is appreciated. That was my "quick and dirty" posting. Normally, I avoid such mistakes in my code.

I know that; we've known you for a very long time! But I couldn't let it go in a public forum...


Thanks. I've edited the posted code to avoid mis-information.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH