-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #130 from fjebaker/fergus/doc-binding
Document parameter binding
- Loading branch information
Showing
9 changed files
with
244 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,72 @@ | ||
# Parameters | ||
# Parameters | ||
|
||
## Parameter binding | ||
|
||
When performing a fit, it is desireable to **bind** certain parameters together. This ensures that they will have the same value; for example, if you were fitting two simultaneous datasets with two [`PowerLaw`](@ref) models, you may want to have different normalisations of the model components, but enforce the power law index to be the same. To achieve this, SpectralFitting has the [`bind!`](@ref) function that applies to your [`FittingProblem`](@ref). | ||
|
||
```@docs | ||
bind! | ||
``` | ||
|
||
!!! note | ||
Bindings are treated not as specific to the model but specific to the [`FittingProblem`](@ref). This is because you may want to use the same model for multiple different datasets, and have slightly different binding requirements for each one (e.g. depending on the instruments you are using). If you do need the same binding applied to two different problems, you can do that with | ||
```julia | ||
append!(prob1.bindings, prob2.bindings) | ||
``` | ||
Caution however, this will only make sense if you are using precisely the same model in both problems. | ||
|
||
|
||
Let's try it out. We'll generate some arbitrary powerlaw spectra with different normalisations and fit them simultaneously. | ||
```julia | ||
using SpectralFitting, Plots | ||
|
||
energy = collect(range(0.1, 10.0, 100)) | ||
|
||
# two different models with different normalisations | ||
model1 = PowerLaw(K = FitParam(100.0), a = FitParam(1.2)) | ||
model2 = PowerLaw(K = FitParam(300.0), a = FitParam(1.22)) | ||
|
||
data1 = simulate(energy, model1, var = 1e-3) | ||
data2 = simulate(energy, model2, var = 1e-3) | ||
|
||
plot(data1, xscale = :log10, yscale = :log10) | ||
plot!(data2, xscale = :log10, yscale = :log10) | ||
``` | ||
|
||
Now we want to fit a single powerlaw model to both of these spectra simultaneously, but with the powerlaw index fixed to be the same in both models. | ||
```julia | ||
model = PowerLaw() | ||
prob = FittingProblem(model => data1, model => data2) | ||
|
||
bind!(prob, :a) | ||
prob | ||
``` | ||
|
||
We can get a better look at our model configuration by using the [`details`](@ref) method: | ||
```julia | ||
details(prob) | ||
``` | ||
|
||
In this printout we see that the `a` parameter of `Model 2` is bound to the `a` parameter of `Model 1`. | ||
|
||
```julia | ||
result = SpectralFitting.fit(prob, LevenbergMarquadt()) | ||
|
||
plot(data1, xscale = :log10, yscale = :log10) | ||
plot!(data2, xscale = :log10, yscale = :log10) | ||
plot!(result[1]) | ||
plot!(result[2]) | ||
``` | ||
|
||
Note that these fits are not perfect, because the underlying data have subtly different power law indices, but our fit is required to enforce the models to have the same value. If we release this requirement, the fit will be better, but the models will be entirely independent. | ||
|
||
```julia | ||
prob = FittingProblem(model => data1, model => data2) | ||
|
||
result = SpectralFitting.fit(prob, LevenbergMarquadt()) | ||
|
||
plot(data1, xscale = :log10, yscale = :log10) | ||
plot!(data2, xscale = :log10, yscale = :log10) | ||
plot!(result[1]) | ||
plot!(result[2]) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
struct BinnedData{V} <: AbstractDataset | ||
domain::V | ||
codomain::V | ||
domain_variance::Union{Nothing,V} | ||
codomain_variance::Union{Nothing,V} | ||
name::String | ||
end | ||
|
||
function BinnedData( | ||
domain, | ||
codomain; | ||
domain_variance = nothing, | ||
codomain_variance = nothing, | ||
name = "[no-name]", | ||
) | ||
@assert length(domain) == length(codomain) + 1 "Data does not look like it is binned!" | ||
BinnedData(domain, codomain, domain_variance, codomain_variance, name) | ||
end | ||
|
||
supports(::Type{<:BinnedData}) = (ContiguouslyBinned(), OneToOne()) | ||
|
||
bin_widths(dataset::BinnedData) = diff(dataset.domain) | ||
objective_units(::BinnedData) = u"counts / (s * keV)" | ||
spectrum_energy(dataset::BinnedData) = | ||
@views (dataset.domain[1:end-1] .+ dataset.domain[2:end]) ./ 2 | ||
|
||
make_model_domain(::ContiguouslyBinned, dataset::BinnedData) = dataset.domain | ||
make_objective(::ContiguouslyBinned, dataset::BinnedData) = dataset.codomain | ||
|
||
make_model_domain(::OneToOne, dataset::BinnedData) = dataset.domain[1:end-1] | ||
make_objective(::OneToOne, dataset::BinnedData) = dataset.codomain | ||
|
||
make_output_domain(layout::AbstractLayout, dataset::BinnedData) = | ||
make_model_domain(layout, dataset) | ||
|
||
function make_objective_variance(::AbstractLayout, dataset::BinnedData{V})::V where {V} | ||
if !isnothing(dataset.codomain_variance) | ||
dataset.codomain_variance | ||
else | ||
# TODO: i dunno just something | ||
ones(eltype(V), length(dataset.codomain)) | ||
end | ||
end | ||
|
||
function objective_transformer(::AbstractLayout, dataset::BinnedData) | ||
function _transformer!!(domain, objective) | ||
@views objective | ||
end | ||
function _transformer!!(output, domain, objective) | ||
@. output = objective | ||
end | ||
_transformer!! | ||
end | ||
|
||
make_label(dataset::BinnedData) = dataset.name | ||
|
||
function _printinfo(io::IO, data::BinnedData) | ||
println( | ||
io, | ||
Crayons.Crayon(foreground = :cyan), | ||
"BinnedData", | ||
Crayons.Crayon(reset = true), | ||
" with ", | ||
Crayons.Crayon(foreground = :cyan), | ||
length(data.domain), | ||
Crayons.Crayon(reset = true), | ||
" data points:", | ||
) | ||
dmin, dmax = prettyfloat.(extrema(data.domain)) | ||
comin, comax = prettyfloat.(extrema(data.codomain)) | ||
descr = """ Name : $(data.name) | ||
. Domain (min/max) : ($dmin, $dmax) | ||
. Codomain (min/max) : ($comin, $comax) | ||
""" | ||
print(io, descr) | ||
end | ||
|
||
export BinnedData |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
|
||
struct InjectiveData{V} <: AbstractDataset | ||
domain::V | ||
codomain::V | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters