FittingData
and ModelFunctions
objects
For the construction of objective functions the data needs to be summarized in a FittingData
object and information about the model needs to be summarized in a ModelFunctions
object.
The FittingData
struct
The FittingData
struct has the following general constructor:
data = FittingData(X,Y,ΔY, distributions = distribution_functions)
The resulting object has the following fields:
data.independent == X
data.dependent == Y
data.errors == ΔY
data.distributions == distributions_functions
If no measurement errors ΔY
are available, the shortened constructor can be used:
FittingData(X,Y, distributions = distribution_functions)
In this case, the default errors ones(length(X))
are used (leading e.g. to the standard least squares objective function: Background: LSQ)
The optional distributions
keyword is used to specify the likelihood distributions (see Background: Posterior probability). If distributions are not specified explicitly, the constructor defaults to normal distributions.
The distributions can be specified as an array of functions, or a single function (the same distribution for all data points) with the signature (y,m,Δy)
, where
y
is the measured dependent variableΔy
is the corresponding errorm
are the values that the model function returns for a given parameter
The ModelFunctions
struct
ModelFunctions
objects have the following general constructor:
model = ModelFunctions(model_function, partial_derivatives = [derivative_functions...])
The resulting object has the following fields:
model.model == model_function
model.partials == [derivative_functions...]
The model function (and the partial derivatives) must have the signature (x,λ)
, where x
is the independent variable and λ
is the parameter (array).
The keyword partials
is optional, but is required for analytical partial derivatives and analytical gradient functions. The partial derivatives w.r.t. the parameter are defined as array of functions.
\[\text{m}(x,\lambda) = \lambda_1 x + \lambda_2 \ ,\quad \frac{\partial \text{m}(x,\lambda)}{\partial \lambda_1} = x\ , \quad \frac{\partial \text{m}(x,\lambda)}{\partial \lambda_1} = 1\]
ModelFunctions((x,λ)-> λ[1]*x + λ[2], partials = [(x,λ)-> x, (x,λ)-> 1])
Additional remarks
When a FittingData
/ModelFunctions
object is created, some rudimentary consistency checks are done, e.g. that all arrays have the same lengths.
julia> FittingData([1,2,3],[1,2],[1,1,1])
ERROR: DimensionMismatch: Arrays for independent data and dependent data do not have the same length.
Since the objects are mutable, the same consistency checks are repeated before objective functions are created. However, it can be useful to make a comprehensive consistency check. For this, a representative parameter (array) is needed:
data = FittingData(X,Y)
model = ModelFunctions((x,λ)-> λ*x)
consistency_check(data,model,1)
If everything works, nothing
is returned, i.e. nothing happens. However, in case of a problem, an error is thrown:
julia> consistency_check(data,model,"1")
ERROR: "Could not evaluate the model function."
Both FittingData
objects and ModelFunctions
objects are mutable for convenience, as they are not performance relevant (only their fields are). However, when objective functions are created, the object fields are copied and enclosed in the objective function, to avoid accidental mutation.
I.e. once an objective function is created, it does not change, even if the FittingData
/ModelFunctions
objects are changed. To apply changes, a new objective function needs to be created.