Miscellaneous

Generate mock datasets

In some case it is useful to test a model for robustness before the emprical data are available for fitting. This can be achieved via the GModelFit.mock() function, whose purpose is to generate a mock dataset which simulates a measurement process by adding random noise to the foreseen ground-truth.

Example

using GModelFit

model = Model(:main => @fd (x, T=3.14) -> sin.(x ./ T) ./ (x ./ T))

# Generate a mock dataset on a specific domain
dom = Domain(1:0.1:50)
data = GModelFit.mock(Measures, model, dom, seed=1)

# Fit model against the mock dataset
bestfit, stats = fit(model, data)
(Components:
───────────┬───────┬───────┬─────────────┬───────────┬───────────┬───────────┬─────────╮
 Component  Type   #Free  Eval. count  Min        Max        Mean       NaN/Inf 
├───────────┼───────┼───────┼─────────────┼───────────┼───────────┼───────────┼─────────┤
 main       FComp  1      29             -0.2172     0.9831    0.08502  0       
╰───────────┴───────┴───────┴─────────────┴───────────┴───────────┴───────────┴─────────╯

Parameters:
───────────┬───────┬────────┬──────────┬───────────┬───────────┬────────┬───────╮
 Component  Type   Param.  Range     Value      Uncert.    Actual  Patch 
├───────────┼───────┼────────┼──────────┼───────────┼───────────┼────────┼───────┤
 main       FComp  T       -Inf:Inf      3.137    0.01237                
╰───────────┴───────┴────────┴──────────┴───────────┴───────────┴────────┴───────╯
, Fit results: #data: 491, #free pars: 1, red. fit stat.:     1.0613, Status: OK      
)

Serialization

A few structures, namely GModelFit.ModelSnapshot, GModelFit.FitStats and Measures{N}, as well as Vector(s) of such structures can be serialized, i.e. stored in a file using a dedicated JSON format. The structures can lated be de-serialized in a separata Julia session without the need to re-run the fitting process used to create them in the first place.

Example

In the following we will generate a few GModelFit.jl objects and serialized them in a file.

using GModelFit

dom = Domain(1:0.1:50)
model = Model(:main => @fd (x, T=3.14) -> sin.(x ./ T) ./ (x ./ T))
data = GModelFit.mock(Measures, model, dom, seed=1)
bestfit, stats = fit(model, data)

# Serialize objects and save in a file
GModelFit.serialize("save_for_future_use.json", bestfit, stats, data)

The same objects can be de-serialized in a different Julia session:

using GModelFit
bestfit, stats, data = GModelFit.deserialize("save_for_future_use.json")
3-element Vector{Any}:
 Components:
───────────┬───────┬───────┬─────────────┬───────────┬───────────┬───────────┬─────────╮
 Component  Type   #Free  Eval. count  Min        Max        Mean       NaN/Inf 
├───────────┼───────┼───────┼─────────────┼───────────┼───────────┼───────────┼─────────┤
 main       FComp  1      29             -0.2172     0.9831    0.08502  0       
╰───────────┴───────┴───────┴─────────────┴───────────┴───────────┴───────────┴─────────╯

Parameters:
───────────┬───────┬────────┬──────────┬───────────┬───────────┬────────┬───────╮
 Component  Type   Param.  Range     Value      Uncert.    Actual  Patch 
├───────────┼───────┼────────┼──────────┼───────────┼───────────┼────────┼───────┤
 main       FComp  T       -Inf:Inf      3.137    0.01237                
╰───────────┴───────┴────────┴──────────┴───────────┴───────────┴────────┴───────╯

 Fit results: #data: 491, #free pars: 1, red. fit stat.:     1.0613, Status: OK      

 Measures{1}: (length: 491)
─────────┬───────────┬───────────┬───────────┬───────────┬───────────┬─────────╮
          Min        Max        Mean       Median     Std. dev.  Nan/Inf 
├─────────┼───────────┼───────────┼───────────┼───────────┼───────────┼─────────┤
 values     -0.3882      1.117    0.08193    0.02601      0.275          
 uncerts    0.06002    0.06985    0.06166    0.06082    0.00229          
╰─────────┴───────────┴───────────┴───────────┴───────────┴───────────┴─────────╯

Quick plot (1D)

The GModelFit.jl package implements Gnuplot.jl recipes to display plots of Measures{1} and ModelSnapshot objects., e.g.:

Example

Create a model, a mock dataset and run a fit:

using GModelFit

dom = Domain(0:0.01:5)
model = Model(:bkg => GModelFit.OffsetSlope(1, 1, 0.1),
              :l1 => GModelFit.Gaussian(1, 2, 0.2),
              :l2 => GModelFit.Gaussian(1, 3, 0.4),
              :main => SumReducer(:bkg, :l1, :l2))
data = GModelFit.mock(Measures, model, dom)
bestfit, stats = fit(model, data)

A plot of the dataset and of the best fit model can be simply obtained with

using Gnuplot
@gp data bestfit

You may also specify axis range, labels, title, etc. using the standard Gnuplot.jl keyword syntax, e.g.:

using Gnuplot
@gp xr=[1, 4.5] xlabel="Wavelength" ylab="Flux" "set key outside" data bestfit

GModelFit internals

(This section deals with GModelFit.jl internals, feel free to skip if not interested.)

During minimization a number of internal data structures are created to avoid reallocating heap memory at each iteration. The most important of such structures are:

  • GModelFit.CompEval: a container to perform component evaluation on a specific domain. This structure is relevant when defining Custom components as it is used to dispatch component evaluation to the proper evaluate! method;

  • GModelFit.ModelEval: a container for a Model evaluation on a specific domain. This structure contains a dictionary of CompEval structures for all components in a model, as well as the values of patched parameters (see Parameter constraints), and is updated at each iteration of the minimizer to reflect the current model evaluaion.

    An important functionality of the ModelEval structure is that it detects the changes in the original Model even after it has been created, e.g.:

    # Create a Model
    model = Model(:comp1 => @fd (x, p1=1) -> p1 .* x)
    
    # Wrap the model into a ModelEval to perform evaluation on a specific domain
    dom = Domain(1:5)
    meval = GModelFit.ModelEval(model, dom)
    
    # Evaluate and print the maximum value
    GModelFit.update!(meval)
    println(maximum(GModelFit.last_evaluation(meval)))
    
    # Add a second component to the original model
    model[:comp2] = @fd (x, comp1, p2=1) -> comp1 .+ p2 .* x.^2
    
    # Re-evaluate the ModelEval (it will automatically detect the addition of :comp2)
    GModelFit.update!(meval)
    println(maximum(GModelFit.last_evaluation(meval)))
    5.0
    30.0
  • GModelFit.Residuals: container for a ModelEval object, a Measures object, a Vector{Float64} to store the normalized residuals, and a minimizer instance. A Residuals object contains all the relevant informations to perform minimization, and is therefore the only argument required for the GModelFit.minimize! function. Since Residuals wraps a ModelEval object it is also able to detect changes in the original model.

    An example of its usage is as follows:

    data = GModelFit.mock(Measures, model, dom)
    resid = GModelFit.Residuals(meval, data, GModelFit.lsqfit())
    GModelFit.minimize!(resid)

    The GModelFit.MultiResiduals has the same purpose in the Multi-dataset fitting case.