15. Multifit
Horace comes with a rich and powerful fitting syntax that is common to the methods used to fit functions or models of \(S(\mathbf{Q}, \omega)\) to one or more datasets.
15.1. Overview
Horace provides a set of methods for fitting sqw
and d1d
, d2d
,
d3d
& d4d
objects, which all share the same fitting syntax and
capabilities. The various forms of multifit enable you to:
fit a function to single dataset
For example, fitting a Gaussian function to a single one-dimensional dataset
fit a function with a global set of parameters to several datasets simultaneously
For example, fitting a model for \(S(\mathbf{Q}, \omega)\) from spin waves to several function
sqw
objects to determine the global intensity scale and magnetic exchange constants that best fit the set of datafit a global foreground function with local background functions
For example, in the previous illustration, allowing an independent linear background for each
sqw
dataset, or even different functional forms for the background for different datasetsfix one or more parameters in the foreground functions and background functions
bind the values of pairs of parameters so that they vary in a fixed ratio in the fit
The last functionality can be very useful if you have a model for \(S(\mathbf{Q}, \omega)\) where you want to have parameters that apply globally (for example, magnetic exchange constants that define spin wave dispersion) but other parameters that can vary independently for each dataset (for example, the spin wave lifetime) . In this instance, you can define the foreground function to be local, then bind the exchange constants across all datasets with ratio unity.
The following multifit variants are available for sqw
and d1d
, d2d
,
d3d
& d4d
objects:
multifit_func
(or equivalentlymultifit
)The foreground and background functions both are functions of the plot axes x1, x2, …
multifit_sqw
The foreground function(s) are functions of \(S(\mathbf{Q}, \omega)\), and the background functions are functions of the plot axes x1, x2, …
multifit_sqw_sqw
The foreground and background function(s) are all functions of \(S(\mathbf{Q}, \omega)\)
15.2. Introduction to setting up and performing a fit
All the variants of multifit share a common procedure for setting up and
performing a fit - they differ only in the form of the functions, which are
either functions of the plot coordinates or qh, qk, ql, en. In what follows we
refer to multifit
, but the same information is true for multifit_func
,
multifit_sqw
, multifit_sqw
, and tobyfit
.
15.2.1. Simple fitting
First you have to create a multifit object with the data you want to fit. You
can give it any name you like - here we’ll use the name kk
>> kk = multifit(w1); % w1 is an object (or array of objects) to be fitted
>> kk = multifit(w1, w2, w3, w4); % several (arrays of) objects to be fitted simultaneously
Next you need to set the fitting functions. In this case, let us assume that you are fitting an array of three objects and that you are going to fit Gaussian functions to all three objects simultaneously:
>> kk = multifit (my_data);
>> kk = kk.set_fun (@gauss);
In the Horace installation there is a folder
(herbert_core\applications\mfit_funcs
) with a selection of fitting
functions, including gauss.m
. A fit function requires a particular set of
input and output arguments (see Fitting functions).
Now we need to provide the starting parameters for the fit. This is a row vector
of the numerical values for the parameters, which in the case of gauss
is
the height, position and standard deviation:
>> kk = kk.set_pin([100, 0, 10]); % height 100, centred on 0, standard deviation 10
By default, multifit will allow all these parameters to float freely in the fit. However, suppose you want to keep the Gaussian centred on the origin. Then you can provide a list of which parameters are allowed to float (1) or are fixed (0). In this example:
>> kk = kk.set_free([1, 0, 1]); % keep the second parameter fixed in the fit
At this point, you can perform a fit:
>> [my_fitted_data, fit_params] = kk.fit();
This returns two arguments: my_fitted_data
is an array of objects which is
the same shape and types as the input data, where that the signal (or
equivalently, the intensity) is set to the calculated values at the final fitted
parameter values; and fit_params
, which is a structure that contains the
fitted parameter values, estimated errors on those fitted values, the value of
chi-squared for the fit and the covariance matrix of the fitted parameters.
If you want to see how the fit is progressing from one iteration to the next, and also get a listing in the Matlab command window of the final fit parameters, you can ask for more verbose output by changing one of the multifit options:
>> kk = kk.set_options('list', 2); % prints highly verbose output to the screen
Other options change the fit convergence criteria, and whether or not the final fit is calculated only for data points that remained once points with zero error bars were removed or for all data points.
Fitting can be computationally very expensive. Before you start fitting, it can be very useful to simulate at the initial parameters to see if your starting point close to expected final values, it can be helpful to check visually using simulate:
>> [my_fitted_data, fit_params] = kk.simulate();
15.2.2. Background functions
One of the nice features of multifit is that as well as fitting a global function (the ‘foreground’) function to all your datsets, you can define local ‘background’ functions, that is functions whose parameters vary independently for each dataset. This can be useful, for example, if you have a model for \(S(\mathbf{Q}, \omega)\) which should apply to all your datasets, but you need to have a linear background that is independent for each dataset. We continue with our example of an array of three datasets which we set up above; to recap:
>> kk = multifit (my_data);
>> kk = kk.set_fun (@gauss);
>> kk = kk.set_pin ([100, 0, 10]);
>> kk = kk.set_free ([1, 0, 1]);
Now let us add an independent linear background for each of the three datasets:
>> kk = kk.set_bfun (@linear_bg); % set_bfun sets the background functions
>> kk = kk.set_bpin ([5.5, 0]); % initial background constant and gradient
>> kk = kk.set_bfree ([1, 0]); % fix the backgroun gradient
Even though only one background function was given in the example above, the default is assume that it applies locally. That is, multifit will assume that we want an independent linear background for each dataset. The same is true of the initial parameter values and the free/fixed parameters.
If you wanted to have different initial starting parameters for each of the linear backgrounds, you should provide a cell array of row vectors, one per dataset:
>> kk = kk.set_bpin ({[5.5, 0]}, [3, 0], [1.2, 0]);
Similarly, if you wanted to fit a linear background to the first two datasets and a quadratic background to the to the third then you should provide a cell array of function handles, one per dataset. Note that three parameters are required for a quadratic background, so you need to give a cell array of starting values as well.
>> kk = kk.set_fun ({@linear_bg, @linear_bg, @quad_bg});
>> kk = kk.set_bpin ({[5.5, 0]}, [3, 0], [1.2, 0, 0]);
15.2.3. Binding parameters
You can bind parameters together so that they are always in a fixed ratio. For example if you wanted the height to always be ten times the standard deviation of the Gaussian, you set a binding descriptor, which is a cell array that gives in sequence the bound parameter, the free parameter, and the ratio of the bound to free parameter:
>> kk = kk.set_bind ({1, 3, 10});
This is a particular case of a binding descriptor. More generally, you need to give the parameter index and the function index for each of the bound and free parameters. The general syntax of a binding descriptor is:
{[ipar_bound, ifun_bound], [ipar_free, ifun_free], ratio}
You can also give more than one binding in one command, by providing a cell array of binding descriptors. For example, if you want to bind the linear background constants together in the example above:
>> kk = kk.set_bbind ({[1, 2], [1, 1], 1}, {[1, 3], [1, 1], 1});
Various defaults apply if you abbreviate the descriptor. For example, if you
don’t give the parameter ratio, then multifit will assume the value determined
by the initial parameter values in set_pin
and set_bpin
. If you don’t give
the bound function index then it is assumed that you mean that the binding
applies for all functions of that type (i.e. the type being foreground or
background functions). The syntax enables complex bindings to be created in
quite a succinct form, and you should navigate to the help for set_bind
(foreground function bindings) and set_bbind
(background function bindings)
from doc sqw/multifit
. You can also accumulate bindings to ones you’ve
already set using add_bind
and add_bbind
.
15.2.4. Semi-global fits
So far we’ve seen how to have a global ‘foreground’ function that applies to all datasets (a Gaussian in the above, but it could be a model for \(S(\mathbf{Q}, \omega)\)) together with independent ‘background’ functions for each dataset. A commonly encountered requirement is to have a model for the foreground where some parameters are global and other are local - for example a single exchange constant in a model for spin waves but independent intensities and inverse lifetimes. To achieve this you can set the background model to be local rather than global, just as teh default is for the background functions. Then you can use binding s to link a parameter across all datasets. For example, returning to our Gaussian foreground model, if we want the position constrained to be the same (but not necessarily zero) for all datasets, but the height and standard deviation allowed to be different:
>> kk = multifit (my_data);
>> kk = kk.set_local_foreground; % override the default
>> kk = kk.set_fun (@gauss); % sets every function to be Gaussian
>> kk = kk.set_pin ([100, 0, 10]); % same initial parameter for all functions
>> kk = kk.set_bind ({2, [2, 1]}); % bind parameter 2 of all functions
The syntax of the last function means that parameter 2 of all foreground functions is bound to parmaeter 2 of the first function. The ratio will be unity because they were all initialised to the same value.
15.3. Summary of commands with multifit
The command set and the inputs they take is considerably richer than the taster
that has been given above. The multifit
help in Matlab that you invoke by
typing doc sqw/multifit
(and any of the variants for d1d
, d2d
,
… objects, and multifit_func
, multifit_sqw
, multifit_sqw_sqw
) is
the gateway to discovering more about the commands and links to example fitting
functions. The summary of the commands is as follows:
To set data:
set_data - Set data, clearing any existing datasets
append_data - Append further datasets to the current set of datasets
remove_data - Remove one or more dataset(s)
replace_data - Replace one or more dataset(s)
To mask data points:
set_mask - Mask data points
add_mask - Mask additional data points
clear_mask - Clear masking for one or more dataset(s)
To set fitting functions:
set_fun - Set foreground fit functions
clear_fun - Clear one or more foreground fit functions
set_bfun - Set background fit functions
clear_bfun - Clear one or more background fit functions
To set initial function parameter values:
set_pin - Set foreground fit function parameters
clear_pin - Clear parameters for one or more foreground fit functions
set_bpin - Set background fit function parameters
clear_bpin - Clear parameters for one or more background fit functions
To set which parameters are fixed or free:
set_free - Set free or fix foreground function parameters
clear_free - Clear all foreground parameters to be free for one or more data sets
set_bfree - Set free or fix background function parameters
clear_bfree - Clear all background parameters to be free for one or more data sets
To bind parameters:
set_bind - Bind foreground parameter values in fixed ratios
add_bind - Add further foreground function bindings
clear_bind - Clear parameter bindings for one or more foreground functions
set_bbind - Bind background parameter values in fixed ratios
add_bbind - Add further background function bindings
clear_bbind - Clear parameter bindings for one or more background functions
To set functions as operating globally or local to a single dataset
set_global_foreground - Specify that there will be a global foreground fit function
set_local_foreground - Specify that there will be local foreground fit function(s)
set_global_background - Specify that there will be a global background fit function
set_local_background - Specify that there will be local background fit function(s)
To fit or simulate:
fit - Fit data
simulate - Simulate datasets at the initial parameter values
Fit control parameters and other options:
set_options - Set options
get_options - Get values of one or more specific options
15.4. Fitting functions
Several multifit
variants are available for sqw
and d1d
, d2d
,
d3d
& d4d
objects. The only substantive difference is the form of the
fit functions they require: either they are functions of the numeric values of
the plot coordinates, or they are function of wavevector in reciprocal lattice
units and energy.
15.4.1. multifit function
This method is identical to multifit_func
.
Foreground function(s): function of the plot axes
x1
,x2
, …,xn
for as many x arrays as there are plot axesBackground function(s): functions of the plot axes
x1
,x2
, …,xn
for as many x arrays as there are plot axes
The general form of a function of plot axis coordinates is:
y = my_function (x1, x2, ..., xn, pars)
or, more generally:
y = my_function (x1, x2, ..., xn, pars, c1, c2, ... cn)
where
x1
,x2
, …,xn
Arrays of x coordinates along each of the n dimensionspars
Parameters needed by the functionc1
,c2
, …,cn
Any further constant arguments needed by the function. For example, they could be the filenames of lookup tables
15.4.2. multifit_func
This method is identical to multifit
.
15.4.3. multifit_sqw
Foreground function(s): functions of \(S(\mathbf{Q}, \omega)\)
Background function(s): functions of the plot axes
x1
,x2
, …,xn
for as many x arrays as there are plot axes
The general form of a model for \(S(\mathbf{Q}, \omega)\) is:
weight = sqwfunc (qh, qk, ql, en, p)
or, more generally:
weight = sqwfunc (qh, qk, ql, en, p, c1, c2, ..., cn)
where
qh
,qk
,ql
,en
Arrays containing the coordinates of a set of pointsp
Vector of parameters needed by the model e.g. [A, js, gam] as intensity, exchange, lifetimec1
,c2
, …,cn
Other constant parameters e.g. file name for look-up table weight Array containing calculated spectral weight
The general form of a function of plot axis coordinates is:
y = my_function (x1, x2, ..., xn, pars)
or, more generally:
y = my_function (x1, x2, ..., xn, pars, c1, c2, ..., cn)
where
x1
,x2
, …,xn
Arrays of x coordinates along each of the n dimensionspars
Parameters needed by the functionc1
,c2
, …,cn
Any further constant arguments needed by the function. For example, they could be the filenames of lookup tables
15.4.4. multifit_sqw_sqw
Foreground function(s): functions of \(S(\mathbf{Q}, \omega)\)
Background function(s): functions of \(S(\mathbf{Q}, \omega)\)
The general form of a model for \(S(\mathbf{Q}, \omega)\) is:
weight = sqwfunc (qh, qk, ql, en, p)
or, more generally:
weight = sqwfunc (qh, qk, ql, en, p, c1, c2, ..)
where
qh
,qk
,ql
,en
Arrays containing the coordinates of a set of pointsp
Vector of parameters needed by the model e.g. [A, js, gam] as intensity, exchange, lifetimec1
,c2
, …,cn
Other constant parameters e.g. file name for look-up table weight Array containing calculated spectral weightweight
Array containing calculated spectral weight
15.5. Parallel fitting
It is possible to use multifit
and its derivatives (tobyfit
,
multifit_sqw
, multifit_sqw_sqw
) in parallel (see
Running Horace in Parallel for more info) by either
enabling HPC options through
>> hpc('on');
or by setting parallel_multifit
directly in the hpc_config
(see
Changing Horace settings)
>> hc = hpc_config;
>> hc.parallel_multifit = true;
Parallel multifit
decomposes the objects passed in into slices which are
distributed between the processors. E.g. if we are fitting three IX_dataset
objects with 100 points between two processors, each processor will receive 50
points from each IX_dataset
.
This decomposition is performed differently for each of the three classes of
fittable objects for each they are divided into N_items/N_procs
:
For
sqw
objects, the items are pixelsFor
dnd
objects, the items are whole bins.For
IX_dataset
objects, the items are points.
Note
If the fitting is run with the -ave
option on an sqw
, then the
decomposition will not split bins, but will distribute whole bins, which may
lead to load imbalance.