diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 7886c797..2bee7b3c 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-06-30T12:34:58","documenter_version":"1.5.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-07-01T10:52:02","documenter_version":"1.5.0"}} \ No newline at end of file diff --git a/dev/datasets/datasets/index.html b/dev/datasets/datasets/index.html index 3c6b6a92..eee905d4 100644 --- a/dev/datasets/datasets/index.html +++ b/dev/datasets/datasets/index.html @@ -6,5 +6,5 @@ match_domains = true, background = nothing, ancillary = nothing, -)source

Dataset abstraction

Datasets must define a small API to make fitting possible. The picture to have in mind when considering the different domains is as follows: the model is trying to predict the objective. It does so by taking in input domain and maps it to some output domain.

That means make_output_domain and make_objective_domain correspond to the $(X,Y)$ values of the data that the model is trying to fit, whilst the model is evaluated on the make_model_domain, which need not be the same as the output domain.

In other cases, the objective_transformer acts to transform the output of the model onto the output domain.

Mathematically, expressing the output domain $X$, the model domain $D$, the model output $M(D)$ and objective $S$, along with the transformer as $T$, then the relationship between the different domains is

\[\hat{S} = T \times M(D),\]

Both $\hat{S}$ and $S$ are defined over $X$. The various fitting operations try to find model paramters that make $\hat{S}$ and $S$ as close as possible.

SpectralFitting.AbstractDatasetType
abstract type AbstractDataset

Abstract type for use in fitting routines. High level representation of some underlying data structures.

Fitting data is considered to have an objective and a domain. As the domain may be, for example, energy bins (high and low), or fourier frequencies (single value), the purpose of this abstraction is to provide some facility for translating between these representations for the models to fit with. This is done by checking that the AbstractLayout of the model and data are compatible, or at least have compatible translations.

Must implement a minimal set of accessor methods. These are paired with objective and domain parlance. Note that these functions are prefixed with make_* and not get_* to represent that there may be allocations or work going into the translation. Usage of these functions should be sparse in the interest of performance.

The arrays returned by the make_* functions must correspond to the AbstractLayout specified by the caller.

Additionally there is an objective transformer that transforms the output of the model onto the output domain:

Finally, to make all of the fitting for different statistical regimes work efficiently, datasets should inform which units are preferred to fit. They may also give the error statistics they prefer, and a label name primarily used to disambiguate:

source
SpectralFitting.make_objective_varianceFunction
make_objective_variance(layout::AbstractLayout, dataset::AbstractDataset)

Make the variance vector associated with each objective point.

source
SpectralFitting.make_objectiveFunction
make_objective(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the target for model fitting. The array must correspond to the data AbstractLayout specified by the layout parameter.

In as far as it can be guarunteed, the memory in the returned array will not be mutated by any fitting procedures.

Domain for this objective should be returned by make_model_domain.

source
SpectralFitting.make_domain_varianceFunction
make_domain_variance(layout::AbstractLayout, dataset::AbstractDataset)

Make the variance vector associated with the domain.

source
SpectralFitting.make_model_domainFunction
make_model_domain(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the domain for the modelling. This is paired with make_domain_variance

source
SpectralFitting.make_output_domainFunction
make_output_domain(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the output domain. That is, in cases where the model input and output map to different domains, the input domain is said to be the model domain, the input domain is said to be the model domain.

The distinction is mainly used for the purposes of simulating data and for visualising data.

source

Underlying data layouts

SpectralFitting.AbstractLayoutType
abstract type AbstractLayout end

The data layout primarily concerns the relationship between the objective and the domain. It is used to work out whether a model and a dataset are fittable, and if not, whether a translation in the output of the model to the domain of the model is possible.

The following methods may be used to interrogate support:

  • preferred_support for inferring the preferred support of a model when multiple supports are possible.
  • common_support to obtain the common support of two structures

The following method is also used to define the support of a model or dataset:

For cases where unit information needs to be propagated, an AbstractLayout can also be used to ensure the units are compatible. To query the units of a layout, use

source
SpectralFitting.OneToOneType
struct OneToOne <: AbstractLayout end

Indicates there is a one-to-one (injective) correspondence between each input value and each output value. That is to say

length(objective) == length(domain)
source
SpectralFitting.ContiguouslyBinnedType
struct ContiguouslyBinned <: AbstractLayout end

Contiguously binned data layout means that the domain describes high and low bins, with the objective being the value in that bin. This means

length(objective) + 1== length(domain)

Note that the contiguous qualifer is to mean there is no gaps in the bins, and that

\[\Delta E_i = E_{i+1} - E_{i}\]

source
SpectralFitting.common_supportFunction
common_support(x, y)

Find the common AbstractLayout of x and y, following the ordering of preferred_support.

source
SpectralFitting.preferred_supportFunction
preferred_support(x)

Get the preferred AbstractLayout of x. If multiple supports are available, the DEFAULT_SUPPORT_ORDERING is followed:

DEFAULT_SUPPORT_ORDERING = (ContiguouslyBinned{Nothing}(nothing), OneToOne{Nothing}(nothing))
source
SpectralFitting.supportsFunction
supports(x::Type)

Used to define whether a given type has support for a specific AbstractLayout. Should return a tuple of the supported layouts. This method should be implemented to express new support, not the query method.

To query, there is

supports(layout::AbstractLayout, x)::Bool

Example

supports(::Type{typeof(x)}) = (OneToOne(),)
-@assert supports(ContiguouslyBinned(), x) == false
source
+)source

Dataset abstraction

Datasets must define a small API to make fitting possible. The picture to have in mind when considering the different domains is as follows: the model is trying to predict the objective. It does so by taking in input domain and maps it to some output domain.

That means make_output_domain and make_objective_domain correspond to the $(X,Y)$ values of the data that the model is trying to fit, whilst the model is evaluated on the make_model_domain, which need not be the same as the output domain.

In other cases, the objective_transformer acts to transform the output of the model onto the output domain.

Mathematically, expressing the output domain $X$, the model domain $D$, the model output $M(D)$ and objective $S$, along with the transformer as $T$, then the relationship between the different domains is

\[\hat{S} = T \times M(D),\]

Both $\hat{S}$ and $S$ are defined over $X$. The various fitting operations try to find model paramters that make $\hat{S}$ and $S$ as close as possible.

SpectralFitting.AbstractDatasetType
abstract type AbstractDataset

Abstract type for use in fitting routines. High level representation of some underlying data structures.

Fitting data is considered to have an objective and a domain. As the domain may be, for example, energy bins (high and low), or fourier frequencies (single value), the purpose of this abstraction is to provide some facility for translating between these representations for the models to fit with. This is done by checking that the AbstractLayout of the model and data are compatible, or at least have compatible translations.

Must implement a minimal set of accessor methods. These are paired with objective and domain parlance. Note that these functions are prefixed with make_* and not get_* to represent that there may be allocations or work going into the translation. Usage of these functions should be sparse in the interest of performance.

The arrays returned by the make_* functions must correspond to the AbstractLayout specified by the caller.

Additionally there is an objective transformer that transforms the output of the model onto the output domain:

Finally, to make all of the fitting for different statistical regimes work efficiently, datasets should inform which units are preferred to fit. They may also give the error statistics they prefer, and a label name primarily used to disambiguate:

source
SpectralFitting.make_objective_varianceFunction
make_objective_variance(layout::AbstractLayout, dataset::AbstractDataset)

Make the variance vector associated with each objective point.

source
SpectralFitting.make_objectiveFunction
make_objective(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the target for model fitting. The array must correspond to the data AbstractLayout specified by the layout parameter.

In as far as it can be guarunteed, the memory in the returned array will not be mutated by any fitting procedures.

Domain for this objective should be returned by make_model_domain.

source
SpectralFitting.make_domain_varianceFunction
make_domain_variance(layout::AbstractLayout, dataset::AbstractDataset)

Make the variance vector associated with the domain.

source
SpectralFitting.make_model_domainFunction
make_model_domain(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the domain for the modelling. This is paired with make_domain_variance

source
SpectralFitting.make_output_domainFunction
make_output_domain(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the output domain. That is, in cases where the model input and output map to different domains, the input domain is said to be the model domain, the input domain is said to be the model domain.

The distinction is mainly used for the purposes of simulating data and for visualising data.

source

Underlying data layouts

SpectralFitting.AbstractLayoutType
abstract type AbstractLayout end

The data layout primarily concerns the relationship between the objective and the domain. It is used to work out whether a model and a dataset are fittable, and if not, whether a translation in the output of the model to the domain of the model is possible.

The following methods may be used to interrogate support:

  • preferred_support for inferring the preferred support of a model when multiple supports are possible.
  • common_support to obtain the common support of two structures

The following method is also used to define the support of a model or dataset:

For cases where unit information needs to be propagated, an AbstractLayout can also be used to ensure the units are compatible. To query the units of a layout, use

source
SpectralFitting.OneToOneType
struct OneToOne <: AbstractLayout end

Indicates there is a one-to-one (injective) correspondence between each input value and each output value. That is to say

length(objective) == length(domain)
source
SpectralFitting.ContiguouslyBinnedType
struct ContiguouslyBinned <: AbstractLayout end

Contiguously binned data layout means that the domain describes high and low bins, with the objective being the value in that bin. This means

length(objective) + 1== length(domain)

Note that the contiguous qualifer is to mean there is no gaps in the bins, and that

\[\Delta E_i = E_{i+1} - E_{i}\]

source
SpectralFitting.common_supportFunction
common_support(x, y)

Find the common AbstractLayout of x and y, following the ordering of preferred_support.

source
SpectralFitting.preferred_supportFunction
preferred_support(x)

Get the preferred AbstractLayout of x. If multiple supports are available, the DEFAULT_SUPPORT_ORDERING is followed:

DEFAULT_SUPPORT_ORDERING = (ContiguouslyBinned{Nothing}(nothing), OneToOne{Nothing}(nothing))
source
SpectralFitting.supportsFunction
supports(x::Type)

Used to define whether a given type has support for a specific AbstractLayout. Should return a tuple of the supported layouts. This method should be implemented to express new support, not the query method.

To query, there is

supports(layout::AbstractLayout, x)::Bool

Example

supports(::Type{typeof(x)}) = (OneToOne(),)
+@assert supports(ContiguouslyBinned(), x) == false
source
diff --git a/dev/datasets/mission-support/index.html b/dev/datasets/mission-support/index.html index d269b2a1..1721b8f3 100644 --- a/dev/datasets/mission-support/index.html +++ b/dev/datasets/mission-support/index.html @@ -1,2 +1,2 @@ -Mission support · SpectralFitting.jl
+Mission support · SpectralFitting.jl
diff --git a/dev/examples/examples/8089ac4e.svg b/dev/examples/examples/f1c14aac.svg similarity index 83% rename from dev/examples/examples/8089ac4e.svg rename to dev/examples/examples/f1c14aac.svg index b58c0c81..0140789c 100644 --- a/dev/examples/examples/8089ac4e.svg +++ b/dev/examples/examples/f1c14aac.svg @@ -1,44 +1,44 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/examples/index.html b/dev/examples/examples/index.html index ad48d8ab..5287db31 100644 --- a/dev/examples/examples/index.html +++ b/dev/examples/examples/index.html @@ -9,4 +9,4 @@ flux = invokemodel(energy, model) -plot(energy[1:end-1], flux)Example block output

Note this energy grid may be arbitrarily spaced, but, like XSPEC, assumes the bins are contiguous, i.e. that the high energy limit of one bin is the low energy limit of the next.

The full model library of available models is listed in Model index.

+plot(energy[1:end-1], flux)Example block output

Note this energy grid may be arbitrarily spaced, but, like XSPEC, assumes the bins are contiguous, i.e. that the high energy limit of one bin is the low energy limit of the next.

The full model library of available models is listed in Model index.

diff --git a/dev/examples/optimizers/index.html b/dev/examples/optimizers/index.html index 64c1e35d..b3d998c9 100644 --- a/dev/examples/optimizers/index.html +++ b/dev/examples/optimizers/index.html @@ -17,4 +17,4 @@ ylims = (1e-3, 1.3) ) -my_plot(data) +my_plot(data) diff --git a/dev/examples/sherpa-example/a0d64fea.svg b/dev/examples/sherpa-example/33d41dae.svg similarity index 67% rename from dev/examples/sherpa-example/a0d64fea.svg rename to dev/examples/sherpa-example/33d41dae.svg index a1d59a93..4f23f140 100644 --- a/dev/examples/sherpa-example/a0d64fea.svg +++ b/dev/examples/sherpa-example/33d41dae.svg @@ -1,243 +1,243 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/sherpa-example/b5ebc148.svg b/dev/examples/sherpa-example/3f79c2ab.svg similarity index 86% rename from dev/examples/sherpa-example/b5ebc148.svg rename to dev/examples/sherpa-example/3f79c2ab.svg index 75d7e3e9..dd06d7eb 100644 --- a/dev/examples/sherpa-example/b5ebc148.svg +++ b/dev/examples/sherpa-example/3f79c2ab.svg @@ -1,56 +1,56 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + + + + + diff --git a/dev/examples/sherpa-example/6f98728d.svg b/dev/examples/sherpa-example/5b6d336c.svg similarity index 84% rename from dev/examples/sherpa-example/6f98728d.svg rename to dev/examples/sherpa-example/5b6d336c.svg index 5c5e296c..cc85ed09 100644 --- a/dev/examples/sherpa-example/6f98728d.svg +++ b/dev/examples/sherpa-example/5b6d336c.svg @@ -1,46 +1,46 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/sherpa-example/c63d3a65.svg b/dev/examples/sherpa-example/7bba8a36.svg similarity index 68% rename from dev/examples/sherpa-example/c63d3a65.svg rename to dev/examples/sherpa-example/7bba8a36.svg index bc0a22c8..a30a0a76 100644 --- a/dev/examples/sherpa-example/c63d3a65.svg +++ b/dev/examples/sherpa-example/7bba8a36.svg @@ -1,321 +1,321 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/sherpa-example/cc8edd68.svg b/dev/examples/sherpa-example/e413030a.svg similarity index 64% rename from dev/examples/sherpa-example/cc8edd68.svg rename to dev/examples/sherpa-example/e413030a.svg index a0918ff2..ed8faf14 100644 --- a/dev/examples/sherpa-example/cc8edd68.svg +++ b/dev/examples/sherpa-example/e413030a.svg @@ -1,319 +1,319 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/sherpa-example/index.html b/dev/examples/sherpa-example/index.html index 4f13bb14..df38e4f8 100644 --- a/dev/examples/sherpa-example/index.html +++ b/dev/examples/sherpa-example/index.html @@ -14,15 +14,15 @@ y_noisy = y .+ (0.2 * randn(length(y))) -scatter(x, y_noisy)Example block output

To make this into a fittable dataset, we observe that our layout is injective (i.e. length(x) == length(y)). This is subtly different from how the majority of spectral models are implemented, which usually assume some kind of binning (length(x) == length(y) + 1). Fortunately, SpectralFitting.jl can track this for us, and do various conversion to make the models work correctly for the data. We need only tell the package what our AbstractLayout is:

data = InjectiveData(x, y_noisy; name = "example")
InjectiveData with 200 data points:
+scatter(x, y_noisy)
Example block output

To make this into a fittable dataset, we observe that our layout is injective (i.e. length(x) == length(y)). This is subtly different from how the majority of spectral models are implemented, which usually assume some kind of binning (length(x) == length(y) + 1). Fortunately, SpectralFitting.jl can track this for us, and do various conversion to make the models work correctly for the data. We need only tell the package what our AbstractLayout is:

data = InjectiveData(x, y_noisy; name = "example")
InjectiveData with 200 data points:
 │   Name                  : example
 │   . Domain (min/max)    : (-5.0000, 5.0)
 │   . Codomain (min/max)  : (-0.42323, 3.3787)
-└ 

The data prints the data card, which provides us some high level information about our data at a glance. We can plot the data trivially using one of the Plots.jl recipes

plot(data, markersize = 3)
Example block output

Next we want to specify a model to fit to this data. Models that are prefixed with XS_ are models that are linked from the XSPEC model library, provided via LibXSPEC_jll. For a full list of the models, see Models index.

Warning

It is advised to use the Julia implemented models. This allows various calculations to benefit from automatic differentiation, efficient multi-threading, GPU offloading, and various other useful things, see Why & how.

model = GaussianLine(μ = FitParam(0.0))
┌ GaussianLine
+└ 

The data prints the data card, which provides us some high level information about our data at a glance. We can plot the data trivially using one of the Plots.jl recipes

plot(data, markersize = 3)
Example block output

Next we want to specify a model to fit to this data. Models that are prefixed with XS_ are models that are linked from the XSPEC model library, provided via LibXSPEC_jll. For a full list of the models, see Models index.

Warning

It is advised to use the Julia implemented models. This allows various calculations to benefit from automatic differentiation, efficient multi-threading, GPU offloading, and various other useful things, see Why & how.

model = GaussianLine(μ = FitParam(0.0))
┌ GaussianLine
 │      K ->  1 ± 0.1  ∈ [ 0, Inf ]   FREE
 │      μ ->  0 ± 0    ∈ [ 0, Inf ]   FREE
 │      σ ->  1 ± 0.1  ∈ [ 0, Inf ]   FREE
-└ 

We can plot our model over the same domain range quite easily too:

plot(data.domain[1:end-1], invokemodel(data.domain, model))
Example block output

Note that we've had to adjust the domain here. As stated before, most models are implemented for binned data, and therefore return one fewer bin than given.

SpectralFitting.jl adopts the SciML problem-solver abstraction, so to fit a model to data we specify a FittingProblem:

prob = FittingProblem(model => data)
┌ FittingProblem:
+└ 

We can plot our model over the same domain range quite easily too:

plot(data.domain[1:end-1], invokemodel(data.domain, model))
Example block output

Note that we've had to adjust the domain here. As stated before, most models are implemented for binned data, and therefore return one fewer bin than given.

SpectralFitting.jl adopts the SciML problem-solver abstraction, so to fit a model to data we specify a FittingProblem:

prob = FittingProblem(model => data)
┌ FittingProblem:
 │   Models:
 │     . GaussianLine{FitParam{Float64}}((1 ± 0.1), (0 ± 0), (1 ± 0.1))
 │   Data:
@@ -33,7 +33,7 @@
 │   . σᵤ    : [9.2751, 0.071547, 0.071547]
 │   . χ²    : 7.7600 
 └ 

The result card tells us a little bit about how successful the fit was. We further inspect the fit by overplotting result on the data:

plot(data, markersize = 3)
-plot!(result)
Example block output

We can create a contour plot of the fit statistic by evaluating the result everywhere on the grid and measuring the statistic:

amps = range(50, 200, 50)
+plot!(result)
Example block output

We can create a contour plot of the fit statistic by evaluating the result everywhere on the grid and measuring the statistic:

amps = range(50, 200, 50)
 devs = range(0.5, 1.2, 50)
 
 stats = [
@@ -51,4 +51,4 @@
     xlabel = "K",
     ylabel = "σ"
 )
-scatter!([result.u[1]], [result.u[3]])
Example block output

Simultaneous fits

+scatter!([result.u[1]], [result.u[3]])Example block output

Simultaneous fits

diff --git a/dev/fitting/index.html b/dev/fitting/index.html index 684a99d6..f4aafb1c 100644 --- a/dev/fitting/index.html +++ b/dev/fitting/index.html @@ -1,2 +1,2 @@ -Fitting spectral models · SpectralFitting.jl
+Fitting spectral models · SpectralFitting.jl
diff --git a/dev/index.html b/dev/index.html index 83a9f285..3f1ec335 100644 --- a/dev/index.html +++ b/dev/index.html @@ -2,4 +2,4 @@ Home · SpectralFitting.jl

SpectralFitting.jl Documentation

Fast and flexible spectral fitting in Julia.

SpectralFitting.jl is a package for defining and using spectral models, with a number of utilities to make model composition easy and invocation fast. SpectralFitting wraps LibXSPEC_jll.jl to expose the library of models from HEASoft XSPEC, and provides helper functions for operating with spectral data from a number of different missions. The package natively uses LsqFit.jl to fit parameters using the Levenberg-Marquardt algorithm, but makes it easy to use Optim.jl for more specialized fitting algorithms, or Turing.jl for Bayesian inference and MCMC.

SpectralFitting is designed to be extended, such that new models are simple to create, and new dataset processing pipelines for different missions are brief to define. Where performance is key, SpectralFitting helps you define fast and AD-compatible surrogates of spectral models using Surrogates.jl, and embed them in the model composition algebra.

To get started, add the AstroRegistry from the University of Bristol and then install:

julia>]
 pkg> registry add https://github.com/astro-group-bristol/AstroRegistry
 pkg> add SpectralFitting

Then use

using SpectralFitting
-# ....

to get started. See Walkthrough for an example walkthrough the package.

For more University of Bristol Astrophysics Group codes, see our GitHub organisation.

+# ....

to get started. See Walkthrough for an example walkthrough the package.

For more University of Bristol Astrophysics Group codes, see our GitHub organisation.

diff --git a/dev/models/composite-models/index.html b/dev/models/composite-models/index.html index afe6f822..5578f55d 100644 --- a/dev/models/composite-models/index.html +++ b/dev/models/composite-models/index.html @@ -1,8 +1,8 @@ Composite models · SpectralFitting.jl

Composite models

The model algebra defined by the AbstractSpectralModelKind yields instances of CompositeModel, nested to various degrees. These composite models are designed to make as much information about the spectral model available at compile-time, such that rich and optimized generated functions may be assembled purely from the Julia types (see Why & how).

SpectralFitting.CompositeModelType
CompositeModel{M1,M2,O} <: AbstractSpectralModel
 CompositeModel(left_model, right_model, op::AbstractCompositeOperator)

Type resulting from operations combining any number of AbstractSpectralModel via the model algebra defined from AbstractSpectralModelKind.

Each operation binary operation in the model algebra is encoded in the parametric types of the CompositeModel, where the operation is given by an AbstractCompositeOperator. Composite models adopt the model kind of the right model, i.e. M2, and obey the model algebra accordingly.

Composite models very rarely need to be constructed directly, and are instead obtained by regular model operations.

Example

model = PhotoelectricAbsorption() * (PowerLaw() + BlackBody())
-typeof(model) <: CompositeModel # true
source
+typeof(model) <: CompositeModel # truesource diff --git a/dev/models/models/index.html b/dev/models/models/index.html index 2233034a..a5cce63f 100644 --- a/dev/models/models/index.html +++ b/dev/models/models/index.html @@ -19,7 +19,7 @@ 0 │ │ └────────────────────────────────────────┘ 0 20 - E (keV)source
SpectralFitting.BlackBodyType
XS_BlackBody(K, T)
  • K: Normalisation.

  • kT: Temperature (keV).

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, BlackBody())
                        BlackBody
        ┌────────────────────────────────────────┐
    0.2 │                                        │
@@ -39,7 +39,7 @@
      0 │:                                    '''│
        └────────────────────────────────────────┘
         0                                     20
-                         E (keV)
source

XSPEC models

XSPEC models frequently have tabular data dependencies, without which the models fail to invoke (see Model data availability). If the data files are known but not present, the XSPEC models will throw an error with instructions for downloading the missing data. If the data files are unknown, Julia may crash catastrophically. If this is the case, often a single line will be printed with the LibXSPEC error, specifying the name of the missing source file. This can be registered as a data dependency of a model using SpectralFitting.register_model_data.

The first time any XSPEC model is invoked, SpectralFitting checks to see whether requisite data is needed, and whether the data is downloaded. Subsequent calls will hit a lookup cache instead to avoid run-time costs of performing this check.

XSPEC models

XSPEC models frequently have tabular data dependencies, without which the models fail to invoke (see Model data availability). If the data files are known but not present, the XSPEC models will throw an error with instructions for downloading the missing data. If the data files are unknown, Julia may crash catastrophically. If this is the case, often a single line will be printed with the LibXSPEC error, specifying the name of the missing source file. This can be registered as a data dependency of a model using SpectralFitting.register_model_data.

The first time any XSPEC model is invoked, SpectralFitting checks to see whether requisite data is needed, and whether the data is downloaded. Subsequent calls will hit a lookup cache instead to avoid run-time costs of performing this check.

SpectralFitting.XS_PowerLawType
XS_PowerLaw(K, a)
  • K: Normalisation.

  • a: Photon index.

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_PowerLaw())
                      XS_PowerLaw
        ┌────────────────────────────────────────┐
    0.5 │                                        │
@@ -59,7 +59,7 @@
      0 │                                        │
        └────────────────────────────────────────┘
         0                                     20
-                         E (keV)
source
SpectralFitting.XS_BlackBodyType
XS_BlackBody(K, T)
  • K: Normalisation.

  • T: Temperature (keV).

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_BlackBody())
                      XS_BlackBody
        ┌────────────────────────────────────────┐
    0.2 │                                        │
@@ -79,7 +79,7 @@
      0 │'                                    '''│
        └────────────────────────────────────────┘
         0                                     20
-                         E (keV)
source
SpectralFitting.XS_BremsStrahlungType
XS_BremsStrahlung(K, T)
  • K: Normalisation.

  • T: Plasma temperature (keV).

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_BremsStrahlung())
                  XS_BremsStrahlung
      ┌────────────────────────────────────────┐
    2 │                                        │
@@ -99,7 +99,7 @@
    0 │  ':....................................│
      └────────────────────────────────────────┘
       0                                     20
-                       E (keV)
source
SpectralFitting.XS_GaussianType
XS_Gaussian(K, E, σ)
  • K: Normalisation

  • E: Line wavelength in Angstrom.

  • σ: Line width in Angstrom.

Example

energy = collect(range(4.0, 8.0, 100))
+                       E (keV)
source
SpectralFitting.XS_GaussianType
XS_Gaussian(K, E, σ)
  • K: Normalisation

  • E: Line wavelength in Angstrom.

  • σ: Line width in Angstrom.

Example

energy = collect(range(4.0, 8.0, 100))
 invokemodel(energy, XS_Gaussian())
                        XS_Gaussian                
         ┌────────────────────────────────────────┐ 
    0.09 │                                        │ 
@@ -119,7 +119,7 @@
       0 │.......:         :......................│ 
         └────────────────────────────────────────┘ 
          0                                     20  
-                          E (keV)                  
source
SpectralFitting.XS_LaorType
XS_Laor(K, lineE, a, inner_r, outer_r, incl)
  • K: Normalisation.

  • lineE: Rest frame line energy (keV).

  • a: Power law dependence of emissitivy. Scales R⁻ᵅ.

  • inner_r: Inner radius of the accretion disk (GM/c).

  • outer_r: Outer radius of the accretion disk (GM/c).

  • θ: Disk inclination angle to line of sight (degrees, 0 is pole on).

Example

energy = collect(range(0.1, 10.0, 100))
+                          E (keV)                  
source
SpectralFitting.XS_LaorType
XS_Laor(K, lineE, a, inner_r, outer_r, incl)
  • K: Normalisation.

  • lineE: Rest frame line energy (keV).

  • a: Power law dependence of emissitivy. Scales R⁻ᵅ.

  • inner_r: Inner radius of the accretion disk (GM/c).

  • outer_r: Outer radius of the accretion disk (GM/c).

  • θ: Disk inclination angle to line of sight (degrees, 0 is pole on).

Example

energy = collect(range(0.1, 10.0, 100))
 invokemodel(energy, XS_Laor())
                          XS_Laor
         ┌────────────────────────────────────────┐
    0.06 │                                        │
@@ -139,7 +139,7 @@
       0 │.......:''                 :............│
         └────────────────────────────────────────┘
          0                                     10
-                          E (keV)
source
SpectralFitting.XS_DiskLineType
XS_DiskLine(K, lineE, β, inner_r, outer_r, incl)
  • K: Normalisation.

  • lineE: Rest frame line energy (keV).

  • β: Power law dependence of emissitivy. If < 10, scales Rᵅ.

  • inner_r: Inner radius of the accretion disk (GM/c).

  • outer_r: Outer radius of the accretion disk (GM/c).

  • θ: Disk inclination angle to line of sight (degrees, 0 is pole on).

Example

energy = collect(range(4.0, 8.0, 100))
+                          E (keV)
source
SpectralFitting.XS_DiskLineType
XS_DiskLine(K, lineE, β, inner_r, outer_r, incl)
  • K: Normalisation.

  • lineE: Rest frame line energy (keV).

  • β: Power law dependence of emissitivy. If < 10, scales Rᵅ.

  • inner_r: Inner radius of the accretion disk (GM/c).

  • outer_r: Outer radius of the accretion disk (GM/c).

  • θ: Disk inclination angle to line of sight (degrees, 0 is pole on).

Example

energy = collect(range(4.0, 8.0, 100))
 invokemodel(energy, XS_DiskLine())
                        XS_DiskLine
         ┌────────────────────────────────────────┐
    0.09 │                                        │
@@ -159,7 +159,7 @@
       0 │...............:'''           :.........│
         └────────────────────────────────────────┘
          4                                      8
-                          E (keV)
source
SpectralFitting.XS_PhotoelectricAbsorptionType
XS_PhotoelectricAbsorption(ηH)
  • ηH: Equivalent hydrogen column (units of 10²² atoms per cm⁻²).

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_PhotoelectricAbsorption())
             XS_PhotoelectricAbsorption
      ┌────────────────────────────────────────┐
    1 │       ...''''''''''''''''''''''''''''''│
@@ -179,7 +179,7 @@
    0 │.:                                      │
      └────────────────────────────────────────┘
       0                                     20
-                       E (keV)
source
SpectralFitting.XS_WarmAbsorptionType
XS_WarmAbsorption(ηH, Ew)
  • ηH: Equivalent hydrogen column (units of 10²² atoms per cm⁻²).

  • Ew: Window energy (keV).

Example

energy = collect(range(0.1, 20.0, 100))
+                       E (keV)
source
SpectralFitting.XS_WarmAbsorptionType
XS_WarmAbsorption(ηH, Ew)
  • ηH: Equivalent hydrogen column (units of 10²² atoms per cm⁻²).

  • Ew: Window energy (keV).

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_WarmAbsorption())
                    XS_WarmAbsorption
        ┌────────────────────────────────────────┐
      1 │':      ...''':'''''''''''''''''''''''''│
@@ -199,7 +199,7 @@
    0.2 │  :                                     │
        └────────────────────────────────────────┘
         0                                     20
-                         E (keV)
source
SpectralFitting.XS_KerrDiskType
XS_KerrDisk(K, lineE, index1, index2, break_r, a, θ, inner_r, outer_r)
  • K: Normalisation.

  • lineE: Rest frame line energy (keV).

  • index1: Emissivity index for inner disk.

  • index2: Emissivity index for outer disk.

  • break_r: Break radius seperating inner and outer disk (gᵣ).

  • a: Dimensionless black hole spin.

  • θ: Disk inclination angle to line of sight (degrees).

  • inner_r: Inner radius of the disk in units of rₘₛ.

  • outer_r: Outer radius of the disk in units of rₘₛ.

  • z: Redshift.

Example

energy = collect(range(0.1, 20.0, 100))
+                         E (keV)
source
SpectralFitting.XS_KerrDiskType
XS_KerrDisk(K, lineE, index1, index2, break_r, a, θ, inner_r, outer_r)
  • K: Normalisation.

  • lineE: Rest frame line energy (keV).

  • index1: Emissivity index for inner disk.

  • index2: Emissivity index for outer disk.

  • break_r: Break radius seperating inner and outer disk (gᵣ).

  • a: Dimensionless black hole spin.

  • θ: Disk inclination angle to line of sight (degrees).

  • inner_r: Inner radius of the disk in units of rₘₛ.

  • outer_r: Outer radius of the disk in units of rₘₛ.

  • z: Redshift.

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_KerrDisk())
                        XS_KerrDisk
         ┌────────────────────────────────────────┐
    0.05 │                                        │
@@ -219,7 +219,7 @@
       0 │.........:'''                    :......│
         └────────────────────────────────────────┘
          0                                      8
-                          E (keV)
source
SpectralFitting.XS_KyrLineType
XS_KyrLine(K, a, θ_obs, inner_r, ms_flag, outer_r, lineE, α, β, break_r, z, limb)
  • K: Normalisation.

  • a: Dimensionless black hole spin.

  • θ: Observer inclination (0 is on pole, degrees).

  • inner_r: Inner radius of the disk in units of GM/c²

  • ms_flag: 0: integrate from rᵢₙ. 1: integrate from rₘₛ.

  • outer_r: Outer radius of the disk in units of GM/c²

  • lineE: Rest frame line energy (keV).

  • α

  • β

  • break_r: Break radius seperating inner and outer disk (GM/c²).

  • z: Overall Doppler shift.

  • limb: 0: isotropic emission, 1: Laor's limb darkening, 2: Haard's limb brightening.

Example

energy = collect(range(0.1, 20.0, 100))
+                          E (keV)
source
SpectralFitting.XS_KyrLineType
XS_KyrLine(K, a, θ_obs, inner_r, ms_flag, outer_r, lineE, α, β, break_r, z, limb)
  • K: Normalisation.

  • a: Dimensionless black hole spin.

  • θ: Observer inclination (0 is on pole, degrees).

  • inner_r: Inner radius of the disk in units of GM/c²

  • ms_flag: 0: integrate from rᵢₙ. 1: integrate from rₘₛ.

  • outer_r: Outer radius of the disk in units of GM/c²

  • lineE: Rest frame line energy (keV).

  • α

  • β

  • break_r: Break radius seperating inner and outer disk (GM/c²).

  • z: Overall Doppler shift.

  • limb: 0: isotropic emission, 1: Laor's limb darkening, 2: Haard's limb brightening.

Example

energy = collect(range(0.1, 20.0, 100))
 invokemodel(energy, XS_KyrLine())
                        XS_KyrLine
         ┌────────────────────────────────────────┐
    0.05 │                                        │
@@ -239,7 +239,7 @@
       0 │.........:'''                    :......│
         └────────────────────────────────────────┘
          0                                      8
-                          E (keV)
source

Wrapping new XSPEC models

SpectralFitting exports a helpful macro to facilitate wrapping additional XSPEC models.

SpectralFitting.@xspecmodelMacro
@xspecmodel [type=Float64] [ff_call_site] model

Used to wrap additional XSPEC models, generating the needed AbstractSpectralModel implementation.

The type keyword specifies the underlying type to coerce input and output arrays to, as different implementations may have incompatible number of bits. The ff_call_site is the foreign fuction call site, which is the first argument to ccall, and follows the same conventions. The model is a struct, which must subtype AbstractSpectralModel.

If the callsite is not specified, the user must implement _unsafe_ffi_invoke!.

Examples

@xspecmodel :C_powerlaw struct XS_PowerLaw{T} <: AbstractSpectralModel{T, Additive}
+                          E (keV)
source

Wrapping new XSPEC models

SpectralFitting exports a helpful macro to facilitate wrapping additional XSPEC models.

SpectralFitting.@xspecmodelMacro
@xspecmodel [type=Float64] [ff_call_site] model

Used to wrap additional XSPEC models, generating the needed AbstractSpectralModel implementation.

The type keyword specifies the underlying type to coerce input and output arrays to, as different implementations may have incompatible number of bits. The ff_call_site is the foreign fuction call site, which is the first argument to ccall, and follows the same conventions. The model is a struct, which must subtype AbstractSpectralModel.

If the callsite is not specified, the user must implement _unsafe_ffi_invoke!.

Examples

@xspecmodel :C_powerlaw struct XS_PowerLaw{T} <: AbstractSpectralModel{T, Additive}
     "Normalisation."
     K::T
     "Photon index."
@@ -249,13 +249,13 @@
 # constructor has default values
 function XS_PowerLaw(; K = FitParam(1.0), a = FitParam(1.0))
     XS_PowerLaw{typeof(K)}(K, a)
-end

We define a new structure XS_PowerLaw with two parameters, but since the model is Additive, only a single parameter (a) is passed to the XSPEC function. The function we bind to this model is :C_powerlaw from the XSPEC C wrappers.

The macro will then generate the following functions

If a callsite was specified, it will also generate:

source
SpectralFitting.register_model_dataFunction
SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, model_data::ModelDataInfo...)
+end

We define a new structure XS_PowerLaw with two parameters, but since the model is Additive, only a single parameter (a) is passed to the XSPEC function. The function we bind to this model is :C_powerlaw from the XSPEC C wrappers.

The macro will then generate the following functions

If a callsite was specified, it will also generate:

source
SpectralFitting.register_model_dataFunction
SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, model_data::ModelDataInfo...)
 SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, remote_and_local::Tuple{String,String}...)
 SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, filenames::String...)
 SpectralFitting.register_model_data(s::Symbol, filenames::String...)

Register filenames as model data associated with the model given by type M or symbol s. This function does not download any files, but rather adds the relevant filenames to a lookup which SpectralFitting.download_model_data consults when invoked, and consequently model data is only downloaded when needed.

Note

It is good practice to use this method immediately after defining a new model with @xspecmodel to register any required datafiles from the HEASoft source code, and therefore keep relevant information together.

Example

# by type
 register_model_data(XS_Laor, "ari.mod")
 # by symbol
-register_model_data(:XS_KyrLine, "KBHline01.fits")
source

Generating model fingerprints

To generate the unicode plot to add as a fingerprint, we use a simple function:

using SpectralFitting, UnicodePlots
+register_model_data(:XS_KyrLine, "KBHline01.fits")
source

Generating model fingerprints

To generate the unicode plot to add as a fingerprint, we use a simple function:

using SpectralFitting, UnicodePlots
 
 function plotmodel(energy, model)
     flux = invokemodel(energy, model)
@@ -289,4 +289,4 @@
    0    '''.................................. 
      └────────────────────────────────────────┘ 
       0                                     20  
-                       E (keV)                  
+ E (keV) diff --git a/dev/models/surrogate-models/710d5f1d.svg b/dev/models/surrogate-models/16d97bdb.svg similarity index 87% rename from dev/models/surrogate-models/710d5f1d.svg rename to dev/models/surrogate-models/16d97bdb.svg index 4f99d753..14c8bdd7 100644 --- a/dev/models/surrogate-models/710d5f1d.svg +++ b/dev/models/surrogate-models/16d97bdb.svg @@ -1,50 +1,50 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/models/surrogate-models/8b1c44d3.svg b/dev/models/surrogate-models/58458ed1.svg similarity index 98% rename from dev/models/surrogate-models/8b1c44d3.svg rename to dev/models/surrogate-models/58458ed1.svg index a2662b40..e5f392cd 100644 --- a/dev/models/surrogate-models/8b1c44d3.svg +++ b/dev/models/surrogate-models/58458ed1.svg @@ -1,62 +1,62 @@ - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + diff --git a/dev/models/surrogate-models/514091c1.svg b/dev/models/surrogate-models/7908ccbe.svg similarity index 98% rename from dev/models/surrogate-models/514091c1.svg rename to dev/models/surrogate-models/7908ccbe.svg index b71330e9..28ebfb00 100644 --- a/dev/models/surrogate-models/514091c1.svg +++ b/dev/models/surrogate-models/7908ccbe.svg @@ -1,62 +1,62 @@ - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + diff --git a/dev/models/surrogate-models/7865fad5.svg b/dev/models/surrogate-models/fe4e2a43.svg similarity index 86% rename from dev/models/surrogate-models/7865fad5.svg rename to dev/models/surrogate-models/fe4e2a43.svg index 452f9c53..c20323cb 100644 --- a/dev/models/surrogate-models/7865fad5.svg +++ b/dev/models/surrogate-models/fe4e2a43.svg @@ -1,48 +1,48 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/models/surrogate-models/index.html b/dev/models/surrogate-models/index.html index 812b8367..d6b21c50 100644 --- a/dev/models/surrogate-models/index.html +++ b/dev/models/surrogate-models/index.html @@ -9,7 +9,7 @@ surrogate, (FitParam(1.0),), (:ηH,) -)

The lower_bounds and upper_bounds must be tuples in the form (E, params...), where E denotes the bounds on the energy range to train over.

source

To facilitate easy surrogate builds, SpectralFitting exports a number of utility functions.

SpectralFitting.make_surrogate_harnessFunction
make_surrogate_harness(
+)

The lower_bounds and upper_bounds must be tuples in the form (E, params...), where E denotes the bounds on the energy range to train over.

source

To facilitate easy surrogate builds, SpectralFitting exports a number of utility functions.

SpectralFitting.make_surrogate_harnessFunction
make_surrogate_harness(
     model::M,
     lowerbounds::T,
     upperbounds::T;
@@ -18,7 +18,7 @@
     S::Type = RadialBasis,
     sample_type = SobolSample(),
     verbose = false,
-)

Creates and optimizes a surrogate model of type S for model, using wrap_model_as_objective and optimize_accuracy! for optimization_samples iterations. Model is initially seeded with seed_samples points prior to optimization.

Warning

Additive models integrate energies to calculate flux, which surrogate models are currently not capable of. Results for Additive models likely to be inaccurate. This will be patched in a future version.

source
SpectralFitting.optimize_accuracy!Function
optimize_accuracy!(
+)

Creates and optimizes a surrogate model of type S for model, using wrap_model_as_objective and optimize_accuracy! for optimization_samples iterations. Model is initially seeded with seed_samples points prior to optimization.

Warning

Additive models integrate energies to calculate flux, which surrogate models are currently not capable of. Results for Additive models likely to be inaccurate. This will be patched in a future version.

source
SpectralFitting.optimize_accuracy!Function
optimize_accuracy!(
     surr::AbstractSurrogate,
     obj::Function,
     lb,
@@ -27,40 +27,40 @@
     maxiters = 200,
     N_truth = 5000,
     verbose = false,
-)

Improve accuracy (faithfullness) of the surrogate model in recreating the objective function.

Samples a new space of N_truth points between lb and ub, and calculates the objective function obj at each. Finds the point with largest MSE between surrogate and objective, and adds the point to the surrogate pool. Repeats maxiters times, adding maxiters points to surrogate model.

Optionally print to stdout the MSE and iteration count with verbose = true.

Note that upper- and lower-bounds should be in the form (E, params...), where E is a single energy and params are the model parameters.

source

Creating a surrogate for XS_PhotoelectricAbsorption

Before we start, let us discuss a number of benefits the use of surrogate models may bring us:

  • SurrogateSpectralModel permit use of automatic differentiation.
  • Surrogate models may be allocation-free depending on setup, whereas XSPEC wrappers will always have to allocate for type-conversions.
  • Surrogate models may be considerably faster, especially for table models.
  • Surrogate models are shareable (see Sharing surrogate models), and are tunable in size.

XS_PhotoelectricAbsorption is an XSPEC model that is wrapped by a thin C-wrapper into Julia. The implementation of this model is a number of Fortran routines from the late 90s, including a tabulation of ~3000 lines of data that has been copied directly into the Fortran source code.

The performance of this model represents its complexity.

using SpectralFitting
+)

Improve accuracy (faithfullness) of the surrogate model in recreating the objective function.

Samples a new space of N_truth points between lb and ub, and calculates the objective function obj at each. Finds the point with largest MSE between surrogate and objective, and adds the point to the surrogate pool. Repeats maxiters times, adding maxiters points to surrogate model.

Optionally print to stdout the MSE and iteration count with verbose = true.

Note that upper- and lower-bounds should be in the form (E, params...), where E is a single energy and params are the model parameters.

source

Creating a surrogate for XS_PhotoelectricAbsorption

Before we start, let us discuss a number of benefits the use of surrogate models may bring us:

  • SurrogateSpectralModel permit use of automatic differentiation.
  • Surrogate models may be allocation-free depending on setup, whereas XSPEC wrappers will always have to allocate for type-conversions.
  • Surrogate models may be considerably faster, especially for table models.
  • Surrogate models are shareable (see Sharing surrogate models), and are tunable in size.

XS_PhotoelectricAbsorption is an XSPEC model that is wrapped by a thin C-wrapper into Julia. The implementation of this model is a number of Fortran routines from the late 90s, including a tabulation of ~3000 lines of data that has been copied directly into the Fortran source code.

The performance of this model represents its complexity.

using SpectralFitting
 
 energy = collect(range(0.1, 20.0, 200))
 model = XS_PhotoelectricAbsorption()
 
 flux = similar(energy)[1:end-1]
199-element Vector{Float64}:
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
+ 1.5e-323
+ 9.0e-323
+ 9.4e-323
+ 1.14e-322
+ 1.2e-322
+ 1.3e-322
+ 1.43e-322
+ 1.5e-322
+ 1.6e-322
+ 2.2e-322
  ⋮
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0

Benchmarking with BenchmarkTools.jl:

using BenchmarkTools
-@benchmark invokemodel!($flux, $energy, $model)
BenchmarkTools.Trial: 4783 samples with 1 evaluation.
- Range (minmax):  1.031 ms 1.670 ms   GC (min … max): 0.00% … 0.00%
- Time  (median):     1.035 ms               GC (median):    0.00%
- Time  (mean ± σ):   1.043 ms ± 50.287 μs   GC (mean ± σ):  0.00% ± 0.00%
+ 2.905e-321
+ 2.915e-321
+ 2.925e-321
+ 2.95e-321
+ 2.955e-321
+ 2.96e-321
+ 2.97e-321
+ 3.004e-321
+ 3.014e-321

Benchmarking with BenchmarkTools.jl:

using BenchmarkTools
+@benchmark invokemodel!($flux, $energy, $model)
BenchmarkTools.Trial: 4765 samples with 1 evaluation.
+ Range (minmax):  1.036 ms 1.671 ms   GC (min … max): 0.00% … 0.00%
+ Time  (median):     1.041 ms               GC (median):    0.00%
+ Time  (mean ± σ):   1.047 ms ± 38.194 μs   GC (mean ± σ):  0.00% ± 0.00%
 
-  ▃█▅▂▁▅▃▁ ▂▂▁                                             ▁
-  ██████████████▇▆▄▆▅▅▄▇▇▅▆▆▆▆▃▃▃▄▅▅▃▁▁▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃ █
-  1.03 ms      Histogram: log(frequency) by time     1.12 ms <
+     ██                                                      
+  ▂▃███▆▄▂▂▃▆▆▅▄▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▁▂▁▂▂▂▂▂▂▂▁▂▂▁▂▂▂▂▂▂▁▂▂▂ ▃
+  1.04 ms        Histogram: frequency by time        1.09 ms <
 
  Memory estimate: 160 bytes, allocs estimate: 3.

The surrogate we'll construct will have to be tailored a little to the data we wish to fit, as we need to specify the parameter ranges our surrogate should learn. For example, we might be interested in energies between $0.1$ and $20$ keV (expressed in our domain), with equivalent hydrogen column $\eta$H anywhere between $10^{-3}$ and $30$. We specify the parameter bounds using tuples:

lower_bounds = (1e-3,)
 upper_bounds = (30.0,)
Note

The first index is always the energy bounds, and the subsequent indices are the parameters in the same order they are defined in the model structure.

Next, we use make_surrogate_harness to build and optimize a surrogate function for our model. By default, the surrogate uses linear radial basis functions, and seeds the coefficients with a number of seed points. This function then improves the accuracy of the model using optimize_accuracy!, until a maximal number of iterations has been reached.

For illustration purposes, we'll omit the accuracy improving step, and perform this ourselves. We can do this by setting optimization_samples = 0 in the keyword arguments:

using Surrogates
@@ -83,19 +83,19 @@
 model.ηH.value = ηh_test
 f = invokemodel(energy, model)
 
-f̂ = harness.surrogate([ηh_test])
Example block output

Now we'll use optimize_accuracy! to improve the faithfulness of our surrogate. This requires making use of wrap_model_as_objective as a little wrapper around our model:

optimize_accuracy!(harness; maxiters=50)
+f̂ = harness.surrogate([ηh_test])
Example block output

Now we'll use optimize_accuracy! to improve the faithfulness of our surrogate. This requires making use of wrap_model_as_objective as a little wrapper around our model:

optimize_accuracy!(harness; maxiters=50)
 
-length(harness.surrogate.x)
52

We can plot the surrogate model again and see the improvement.

new_f̂ = harness.surrogate([ηh_test])
Example block output

Tight. We can also inspect the memory footprint of our model:

# in bytes
+length(harness.surrogate.x)
52

We can plot the surrogate model again and see the improvement.

new_f̂ = harness.surrogate([ηh_test])
Example block output

Tight. We can also inspect the memory footprint of our model:

# in bytes
 Base.summarysize(harness)
172072

This may be reduced by lowering maxiters in optimize_accuracy! at the cost of decreasing faithfulness. However, compare this to the Fortran tabulated source file in the XSPEC source code, which is approximately 224 Kb. The surrogate model with all it's training data is of the same order.

Using a surrogate spectral model

Now that we have the surrogate model, we use SurrogateSpectralModel to wrap it into an AbstractSpectralModel. The constructor also needs to know the model kind, have a copy of the model parameters, and know which symbols to represent the parameters with.

sm = make_model(harness)
┌ SurrogateSpectralModel
 │      ηH ->  22.9 ± 0.1  ∈ [ 0, Inf ]   FREE

We can now use the familiar API and attempt to benchmark the performance:

@benchmark invokemodel!($flux, $energy, $sm)
BenchmarkTools.Trial: 10000 samples with 10 evaluations.
- Range (minmax):  1.771 μs 23.725 μs   GC (min … max): 0.00% … 0.00%
- Time  (median):     2.527 μs                GC (median):    0.00%
- Time  (mean ± σ):   2.454 μs ± 722.757 ns   GC (mean ± σ):  0.00% ± 0.00%
+ Range (minmax):  1.758 μs 20.150 μs   GC (min … max): 0.00% … 0.00%
+ Time  (median):     2.502 μs                GC (median):    0.00%
+ Time  (mean ± σ):   2.430 μs ± 739.831 ns   GC (mean ± σ):  0.00% ± 0.00%
 
-   ▄▇                      ▂▇   ▃█▅                           
-  ▃██▆▃▂▂▂▂▁▁▂▂▂▁▂▁▁▁▂▂▂▁▂▃██▇▄████▅▄▆▇▆▅▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
-  1.77 μs         Histogram: frequency by time        3.24 μs <
+   ▆                       ▄█    ▆▆                            
+  ▅██▃▂▂▂▂▂▂▁▂▁▂▂▁▁▁▂▁▁▁▁▁▃██▄▃███▅▃▃▇▇▅▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
+  1.76 μs         Histogram: frequency by time        3.24 μs <
 
  Memory estimate: 1.77 KiB, allocs estimate: 1.

Comparing this to the initial benchmark of XS_PhotoelectricAbsorption, we see about a significant speedup, with no allocations, and this surrogate model is now automatic differentiation ready.

Evaluating the model

p_range = collect(range(1.0, 30.0))
 
@@ -105,11 +105,11 @@
 end
 fluxes_mat = reduce(hcat, fluxes_vecs)
 
-surface(p_range, energy[1:end-1], fluxes_mat, xlabel = "ηH", ylabel = "E", zlabel = "f", title = "Model")
Example block output
s_fluxes_vecs = map(p_range) do p
+surface(p_range, energy[1:end-1], fluxes_mat, xlabel = "ηH", ylabel = "E", zlabel = "f", title = "Model")
Example block output
s_fluxes_vecs = map(p_range) do p
     sm.params[1].value = p
     display(sm)
     f = invokemodel(energy, sm)
 end
 s_fluxes_mat = reduce(hcat, s_fluxes_vecs)
 
-surface(p_range, energy[1:end-1], s_fluxes_mat, xlabel = "ηH", ylabel = "E", zlabel = "f", title = "Surrogate")
Example block output

Sharing surrogate models

To export and import surrogate models, JLD2.jl is recommended.

+surface(p_range, energy[1:end-1], s_fluxes_mat, xlabel = "ηH", ylabel = "E", zlabel = "f", title = "Surrogate")Example block output

Sharing surrogate models

To export and import surrogate models, JLD2.jl is recommended.

diff --git a/dev/models/using-models/index.html b/dev/models/using-models/index.html index 126224e1..a84c5792 100644 --- a/dev/models/using-models/index.html +++ b/dev/models/using-models/index.html @@ -103,28 +103,28 @@ 0.1999999999999993 0.20000000000000284 0.1999999999999993 - 0.1999999999999993
Note

To add new XSPEC or foreign function models, see Wrapping new XSPEC models.

Model abstraction

All spectral models are a sub-type of AbstractSpectralModel.

SpectralFitting.AbstractSpectralModelType
abstract type AbstractSpectralModel{T,K<:AbstractSpectralModelKind} end

Supertype of all spectral models, tracking the number type T and AbstractSpectralModelKind denoted K.

Implementation

Sub-types must implement the following interface (see the function's documentation for examples):

Usage

The available API for a spectral model is detailed below:

The following query functions exist:

Model reflection is supported by the following functions. These are intended for internal use and are not exported.

The parametric type parameter T is the number type of the model and K defines the AbstractSpectralModelKind.

source
SpectralFitting.invoke!Function
SpectralFitting.invoke!(output, domain, M::Type{<:AbstractSpectralModel}, params...)

Used to define the behaviour of models. Should calculate the output of the model and write in-place into output. The model parameters are passed in the model structure.

Warning

This function should not be called directly. Use invokemodel instead. invoke! is only to define the model, not to use it. Users should always call models using invokemodel or invokemodel! to ensure normalisations and closures are accounted for.

Example

Base.@kwdef struct MyModel{T} <: AbstractSpectralModel{T,Multiplicative}
+ 0.1999999999999993
Note

To add new XSPEC or foreign function models, see Wrapping new XSPEC models.

Model abstraction

All spectral models are a sub-type of AbstractSpectralModel.

SpectralFitting.AbstractSpectralModelType
abstract type AbstractSpectralModel{T,K<:AbstractSpectralModelKind} end

Supertype of all spectral models, tracking the number type T and AbstractSpectralModelKind denoted K.

Implementation

Sub-types must implement the following interface (see the function's documentation for examples):

Usage

The available API for a spectral model is detailed below:

The following query functions exist:

Model reflection is supported by the following functions. These are intended for internal use and are not exported.

The parametric type parameter T is the number type of the model and K defines the AbstractSpectralModelKind.

source
SpectralFitting.invoke!Function
SpectralFitting.invoke!(output, domain, M::Type{<:AbstractSpectralModel}, params...)

Used to define the behaviour of models. Should calculate the output of the model and write in-place into output. The model parameters are passed in the model structure.

Warning

This function should not be called directly. Use invokemodel instead. invoke! is only to define the model, not to use it. Users should always call models using invokemodel or invokemodel! to ensure normalisations and closures are accounted for.

Example

Base.@kwdef struct MyModel{T} <: AbstractSpectralModel{T,Multiplicative}
     p1::T = FitParam(1.0)
     p2::T = FitParam(2.0)
     p3::T = FitParam(3.0)
 end

would have the arguments passed to invoke! as

function SpectralFitting.invoke!(output, domain, model::MyModel)
     # ...
-end
source
SpectralFitting.modelkindFunction
modelkind(M::Type{<:AbstractSpectralModel})
-modelkind(::AbstractSpectralModel)

Return the kind of model given by M: either Additive, Multiplicative, or Convolutional.

source
SpectralFitting.numbertypeFunction
numbertype(::AbstractSpectralModel)

Get the numerical type of the model. This goes through FitParam, so that the number type returned is as close to a primative as possible.

See also paramtype.

Example

numbertype(PowerLaw()) == Float64
source

Model methods

SpectralFitting.invokemodelFunction
invokemodel(domain, model::AbstractSpectralModel)

Invoke the AbstractSpectralModel given by model over the domain domain.

This function will perform any normalisation or post-processing tasks that a specific model kind may require, e.g. multiplying by a normalisation constant for Additive models.

Note

invokemodel allocates the needed output arrays based on the element type of free_params to allow automatic differentation libraries to calculate parameter gradients.

In-place non-allocating variants are the invokemodel! functions.

Example

model = PowerLaw()
+end
source
SpectralFitting.modelkindFunction
modelkind(M::Type{<:AbstractSpectralModel})
+modelkind(::AbstractSpectralModel)

Return the kind of model given by M: either Additive, Multiplicative, or Convolutional.

source
SpectralFitting.numbertypeFunction
numbertype(::AbstractSpectralModel)

Get the numerical type of the model. This goes through FitParam, so that the number type returned is as close to a primative as possible.

See also paramtype.

Example

numbertype(PowerLaw()) == Float64
source

Model methods

SpectralFitting.invokemodelFunction
invokemodel(domain, model::AbstractSpectralModel)

Invoke the AbstractSpectralModel given by model over the domain domain.

This function will perform any normalisation or post-processing tasks that a specific model kind may require, e.g. multiplying by a normalisation constant for Additive models.

Note

invokemodel allocates the needed output arrays based on the element type of free_params to allow automatic differentation libraries to calculate parameter gradients.

In-place non-allocating variants are the invokemodel! functions.

Example

model = PowerLaw()
 domain = collect(range(0.1, 20.0, 100))
 
-invokemodel(domain, model)
source
SpectralFitting.invokemodel!Function
invokemodel!(output, domain, model)
 invokemodel!(output, domain, model, params::AbstractVector)
 invokemodel!(output, domain, model, params::ParameterCache)

In-place variant of invokemodel, calculating the output of an AbstractSpectralModel given by model, optionally overriding the parameters using a ParameterCache or an AbstractVector.

The output may not necessarily be a single vector, and one should use allocate_model_output to allocate the output structure.

Example

model = PowerLaw()
 domain = collect(range(0.1, 20.0, 100))
 output = allocate_model_output(model, domain)
-invokemodel!(output, domain, model)
source

Model algebra

Models exist as three different kinds, defined by an AbstractSpectralModelKind trait.

Model algebra

Models exist as three different kinds, defined by an AbstractSpectralModelKind trait.

SpectralFitting.AdditiveType
Additive <: AbstractSpectralModelKind
-Additive()

Additive models are effectively the sources of photons, and are the principle building blocks of composite models. Every additive model has a normalisation parameter which re-scales the output by a constant factor K.

Note

Defining custom additive models requires special care. See Defining new models.

source
SpectralFitting.MultiplicativeType
Multiplicative <: AbstractSpectralModelKind
-Multiplicative()

Multiplicative models act on Additive models, by element-wise multiplying the output in each domain bin of the additive model by a different factor.

source

Model data availability

Many of the XSPEC implemented models use tabular data, such as FITS, and return results interpolated from these pre-calculated tables. In some cases, these table models have data files that are multiple gigabytes in size, and would be very unwieldy to ship indiscriminantly. SpectralFitting attempts to circumnavigate this bloat by downloading the model data on an ut opus basis.

SpectralFitting.AdditiveType
Additive <: AbstractSpectralModelKind
+Additive()

Additive models are effectively the sources of photons, and are the principle building blocks of composite models. Every additive model has a normalisation parameter which re-scales the output by a constant factor K.

Note

Defining custom additive models requires special care. See Defining new models.

source
SpectralFitting.MultiplicativeType
Multiplicative <: AbstractSpectralModelKind
+Multiplicative()

Multiplicative models act on Additive models, by element-wise multiplying the output in each domain bin of the additive model by a different factor.

source

Model data availability

Many of the XSPEC implemented models use tabular data, such as FITS, and return results interpolated from these pre-calculated tables. In some cases, these table models have data files that are multiple gigabytes in size, and would be very unwieldy to ship indiscriminantly. SpectralFitting attempts to circumnavigate this bloat by downloading the model data on an ut opus basis.

SpectralFitting.download_model_dataFunction
SpectralFitting.download_model_data(model::AbstractSpectralModel; kwargs...)
 SpectralFitting.download_model_data(M::Type{<:AbstractSpectralModel}; kwargs...)
-SpectralFitting.download_model_data(s::Symbol; kwargs...)

Downloads the model data for a model specified either by model, type M, or symbol s. Datafiles associated with a specific model may be registered using SpectralFitting.register_model_data. The download is currently unconfigurable, but permits slight control via a number of keyword arguments:

  • progress::Bool = true

Display a progress bar for the download.

  • model_source_url::String = "http://www.star.bris.ac.uk/fbaker/XSPEC-model-data"

The source URL used to download the model data.

All standard XSPEC spectral model data is currently being hosted on the University of Bristol astrophysics servers, and should be persistently available to anyone.

source

Special care must be taken if new XSPEC models are wrapped to ensure the data is available. For more on this, see Wrapping new XSPEC models.

Model data may also alternatively be copied in by-hand from a HEASoft XSPEC source directory. In this case, the location to copy the data to may be determined via joinpath(SpectralFitting.LibXSPEC_jll.artifact_dir, "spectral", "modelData").

+SpectralFitting.download_model_data(s::Symbol; kwargs...)

Downloads the model data for a model specified either by model, type M, or symbol s. Datafiles associated with a specific model may be registered using SpectralFitting.register_model_data. The download is currently unconfigurable, but permits slight control via a number of keyword arguments:

  • progress::Bool = true

Display a progress bar for the download.

  • model_source_url::String = "http://www.star.bris.ac.uk/fbaker/XSPEC-model-data"

The source URL used to download the model data.

All standard XSPEC spectral model data is currently being hosted on the University of Bristol astrophysics servers, and should be persistently available to anyone.

source

Special care must be taken if new XSPEC models are wrapped to ensure the data is available. For more on this, see Wrapping new XSPEC models.

Model data may also alternatively be copied in by-hand from a HEASoft XSPEC source directory. In this case, the location to copy the data to may be determined via joinpath(SpectralFitting.LibXSPEC_jll.artifact_dir, "spectral", "modelData").

diff --git a/dev/objects.inv b/dev/objects.inv index 1fecf935..130d1c9a 100644 Binary files a/dev/objects.inv and b/dev/objects.inv differ diff --git a/dev/parameters/index.html b/dev/parameters/index.html index ee907327..86ba6145 100644 --- a/dev/parameters/index.html +++ b/dev/parameters/index.html @@ -1,2 +1,2 @@ -Parameters · SpectralFitting.jl
+Parameters · SpectralFitting.jl
diff --git a/dev/reference/index.html b/dev/reference/index.html index 2f280ab5..ca2ae5d5 100644 --- a/dev/reference/index.html +++ b/dev/reference/index.html @@ -1,29 +1,29 @@ -Reference · SpectralFitting.jl

API reference

Utility functions for defining new models

SpectralFitting.finite_diff_kernel!Function
finite_diff_kernel!(f::Function, flux, energy)

Calculates the finite difference of the function f over the energy bin between the high and low bin edges, via

\[c_i = f(E_{i,\text{high}}) - f(E_{i,\text{low}}),\]

similar to evaluating the limits of the integral between $E_{i,\text{high}}$ and $E_{i,\text{low}}$.

This utility function is primarily used for Additive models to ensure the flux per bin is normalised for the energy over the bin.

source
SpectralFitting.wrap_model_as_objectiveFunction
wrap_model_as_objective(model::AbstractSpectralModel; ΔE = 1e-1)
-wrap_model_as_objective(M::Type{<:AbstractSpectralModel}; ΔE = 1e-1)

Wrap a spectral model into an objective function for building/optimizing a surrogate model. Returns an anonymous function taking the tuple (E, params...) as the argument, and returning a single flux value.

source

General reference

Base.copyMethod
Base.copy(m::AbstractTableModel)

Create a copy of an AbstractTableModel. This will copy all fields except the table field, which is assumed to be a constant set of values that can be shared by multiple copies.

When this is not the case, the user should redefine Base.copy for their particular table model to copy the table as needed.

source
Base.copyMethod
Base.copy(m::AsConvolution)

Creates a copy of an AsConvolution wrapped model. Will make a deepcopy of the cache to elimiate possible thread contention, but does not copy the domain.

source
SpectralFitting._accumulated_indicesMethod
_accumulated_indices(items)

items is a tuple or vector of lengths n1, n2, ...

Returns a tuple or array with same length as items, which gives the index boundaries of an array with size n1 + n2 + ....

source
SpectralFitting._safe_ffi_invoke!Method
function _safe_ffi_invoke!(output, input, params, ModelType::Type{<:AbstractSpectralModel})

Wrapper to do a foreign function call to an XSPEC model.

source
SpectralFitting._subtract_background!Method

Does the background subtraction and returns units of counts. That means we have multiplied through by a factor $t_D$ relative to the reference equation (2.3) in the XSPEC manual.

source
SpectralFitting._unsafe_ffi_invoke!Method
function _unsafe_ffi_invoke!(
+Reference · SpectralFitting.jl

API reference

Utility functions for defining new models

SpectralFitting.finite_diff_kernel!Function
finite_diff_kernel!(f::Function, flux, energy)

Calculates the finite difference of the function f over the energy bin between the high and low bin edges, via

\[c_i = f(E_{i,\text{high}}) - f(E_{i,\text{low}}),\]

similar to evaluating the limits of the integral between $E_{i,\text{high}}$ and $E_{i,\text{low}}$.

This utility function is primarily used for Additive models to ensure the flux per bin is normalised for the energy over the bin.

source
SpectralFitting.wrap_model_as_objectiveFunction
wrap_model_as_objective(model::AbstractSpectralModel; ΔE = 1e-1)
+wrap_model_as_objective(M::Type{<:AbstractSpectralModel}; ΔE = 1e-1)

Wrap a spectral model into an objective function for building/optimizing a surrogate model. Returns an anonymous function taking the tuple (E, params...) as the argument, and returning a single flux value.

source

General reference

Base.copyMethod
Base.copy(m::AbstractTableModel)

Create a copy of an AbstractTableModel. This will copy all fields except the table field, which is assumed to be a constant set of values that can be shared by multiple copies.

When this is not the case, the user should redefine Base.copy for their particular table model to copy the table as needed.

source
Base.copyMethod
Base.copy(m::AsConvolution)

Creates a copy of an AsConvolution wrapped model. Will make a deepcopy of the cache to elimiate possible thread contention, but does not copy the domain.

source
SpectralFitting._accumulated_indicesMethod
_accumulated_indices(items)

items is a tuple or vector of lengths n1, n2, ...

Returns a tuple or array with same length as items, which gives the index boundaries of an array with size n1 + n2 + ....

source
SpectralFitting._safe_ffi_invoke!Method
function _safe_ffi_invoke!(output, input, params, ModelType::Type{<:AbstractSpectralModel})

Wrapper to do a foreign function call to an XSPEC model.

source
SpectralFitting._subtract_background!Method

Does the background subtraction and returns units of counts. That means we have multiplied through by a factor $t_D$ relative to the reference equation (2.3) in the XSPEC manual.

source
SpectralFitting.count_errorMethod
count_error(k, σ)

Gives the error on k mean photon counts to a significance of σ standard deviations about the mean.

Derived from likelihood of binomial distributions being the beta function.

source
SpectralFitting.count_errorMethod
count_error(k, σ)

Gives the error on k mean photon counts to a significance of σ standard deviations about the mean.

Derived from likelihood of binomial distributions being the beta function.

source
SpectralFitting.download_model_dataMethod
SpectralFitting.download_model_data(model::AbstractSpectralModel; kwargs...)
 SpectralFitting.download_model_data(M::Type{<:AbstractSpectralModel}; kwargs...)
-SpectralFitting.download_model_data(s::Symbol; kwargs...)

Downloads the model data for a model specified either by model, type M, or symbol s. Datafiles associated with a specific model may be registered using SpectralFitting.register_model_data. The download is currently unconfigurable, but permits slight control via a number of keyword arguments:

  • progress::Bool = true

Display a progress bar for the download.

  • model_source_url::String = "http://www.star.bris.ac.uk/fbaker/XSPEC-model-data"

The source URL used to download the model data.

All standard XSPEC spectral model data is currently being hosted on the University of Bristol astrophysics servers, and should be persistently available to anyone.

source
SpectralFitting.finite_diff_kernel!Method
finite_diff_kernel!(f::Function, flux, energy)

Calculates the finite difference of the function f over the energy bin between the high and low bin edges, via

\[c_i = f(E_{i,\text{high}}) - f(E_{i,\text{low}}),\]

similar to evaluating the limits of the integral between $E_{i,\text{high}}$ and $E_{i,\text{low}}$.

This utility function is primarily used for Additive models to ensure the flux per bin is normalised for the energy over the bin.

source
SpectralFitting.folded_energyMethod
folded_energy(response::ResponseMatrix)

Get the contiguously binned energy corresponding to the output (folded) domain of the response matrix. That is, the channel energies as used by the spectrum.

source
SpectralFitting.invoke!Method
SpectralFitting.invoke!(output, domain, M::Type{<:AbstractSpectralModel}, params...)

Used to define the behaviour of models. Should calculate the output of the model and write in-place into output. The model parameters are passed in the model structure.

Warning

This function should not be called directly. Use invokemodel instead. invoke! is only to define the model, not to use it. Users should always call models using invokemodel or invokemodel! to ensure normalisations and closures are accounted for.

Example

Base.@kwdef struct MyModel{T} <: AbstractSpectralModel{T,Multiplicative}
+SpectralFitting.download_model_data(s::Symbol; kwargs...)

Downloads the model data for a model specified either by model, type M, or symbol s. Datafiles associated with a specific model may be registered using SpectralFitting.register_model_data. The download is currently unconfigurable, but permits slight control via a number of keyword arguments:

  • progress::Bool = true

Display a progress bar for the download.

  • model_source_url::String = "http://www.star.bris.ac.uk/fbaker/XSPEC-model-data"

The source URL used to download the model data.

All standard XSPEC spectral model data is currently being hosted on the University of Bristol astrophysics servers, and should be persistently available to anyone.

source
SpectralFitting.finite_diff_kernel!Method
finite_diff_kernel!(f::Function, flux, energy)

Calculates the finite difference of the function f over the energy bin between the high and low bin edges, via

\[c_i = f(E_{i,\text{high}}) - f(E_{i,\text{low}}),\]

similar to evaluating the limits of the integral between $E_{i,\text{high}}$ and $E_{i,\text{low}}$.

This utility function is primarily used for Additive models to ensure the flux per bin is normalised for the energy over the bin.

source
SpectralFitting.folded_energyMethod
folded_energy(response::ResponseMatrix)

Get the contiguously binned energy corresponding to the output (folded) domain of the response matrix. That is, the channel energies as used by the spectrum.

source
SpectralFitting.invoke!Method
SpectralFitting.invoke!(output, domain, M::Type{<:AbstractSpectralModel}, params...)

Used to define the behaviour of models. Should calculate the output of the model and write in-place into output. The model parameters are passed in the model structure.

Warning

This function should not be called directly. Use invokemodel instead. invoke! is only to define the model, not to use it. Users should always call models using invokemodel or invokemodel! to ensure normalisations and closures are accounted for.

Example

Base.@kwdef struct MyModel{T} <: AbstractSpectralModel{T,Multiplicative}
     p1::T = FitParam(1.0)
     p2::T = FitParam(2.0)
     p3::T = FitParam(3.0)
 end

would have the arguments passed to invoke! as

function SpectralFitting.invoke!(output, domain, model::MyModel)
     # ...
-end
source
SpectralFitting.invokemodel!Method
invokemodel!(output, domain, model)
 invokemodel!(output, domain, model, params::AbstractVector)
 invokemodel!(output, domain, model, params::ParameterCache)

In-place variant of invokemodel, calculating the output of an AbstractSpectralModel given by model, optionally overriding the parameters using a ParameterCache or an AbstractVector.

The output may not necessarily be a single vector, and one should use allocate_model_output to allocate the output structure.

Example

model = PowerLaw()
 domain = collect(range(0.1, 20.0, 100))
 output = allocate_model_output(model, domain)
-invokemodel!(output, domain, model)
source
SpectralFitting.invokemodelMethod
invokemodel(domain, model::AbstractSpectralModel)

Invoke the AbstractSpectralModel given by model over the domain domain.

This function will perform any normalisation or post-processing tasks that a specific model kind may require, e.g. multiplying by a normalisation constant for Additive models.

Note

invokemodel allocates the needed output arrays based on the element type of free_params to allow automatic differentation libraries to calculate parameter gradients.

In-place non-allocating variants are the invokemodel! functions.

Example

model = PowerLaw()
+invokemodel!(output, domain, model)
source
SpectralFitting.invokemodelMethod
invokemodel(domain, model::AbstractSpectralModel)

Invoke the AbstractSpectralModel given by model over the domain domain.

This function will perform any normalisation or post-processing tasks that a specific model kind may require, e.g. multiplying by a normalisation constant for Additive models.

Note

invokemodel allocates the needed output arrays based on the element type of free_params to allow automatic differentation libraries to calculate parameter gradients.

In-place non-allocating variants are the invokemodel! functions.

Example

model = PowerLaw()
 domain = collect(range(0.1, 20.0, 100))
 
-invokemodel(domain, model)
source
SpectralFitting.make_objectiveMethod
make_objective(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the target for model fitting. The array must correspond to the data AbstractLayout specified by the layout parameter.

In as far as it can be guarunteed, the memory in the returned array will not be mutated by any fitting procedures.

Domain for this objective should be returned by make_model_domain.

source
SpectralFitting.make_output_domainMethod
make_output_domain(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the output domain. That is, in cases where the model input and output map to different domains, the input domain is said to be the model domain, the input domain is said to be the model domain.

The distinction is mainly used for the purposes of simulating data and for visualising data.

source
SpectralFitting.make_objectiveMethod
make_objective(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the target for model fitting. The array must correspond to the data AbstractLayout specified by the layout parameter.

In as far as it can be guarunteed, the memory in the returned array will not be mutated by any fitting procedures.

Domain for this objective should be returned by make_model_domain.

source
SpectralFitting.make_output_domainMethod
make_output_domain(layout::AbstractLayout, dataset::AbstractDataset)

Returns the array used as the output domain. That is, in cases where the model input and output map to different domains, the input domain is said to be the model domain, the input domain is said to be the model domain.

The distinction is mainly used for the purposes of simulating data and for visualising data.

source
SpectralFitting.make_surrogate_harnessMethod
make_surrogate_harness(
     model::M,
     lowerbounds::T,
     upperbounds::T;
@@ -32,8 +32,8 @@
     S::Type = RadialBasis,
     sample_type = SobolSample(),
     verbose = false,
-)

Creates and optimizes a surrogate model of type S for model, using wrap_model_as_objective and optimize_accuracy! for optimization_samples iterations. Model is initially seeded with seed_samples points prior to optimization.

Warning

Additive models integrate energies to calculate flux, which surrogate models are currently not capable of. Results for Additive models likely to be inaccurate. This will be patched in a future version.

source
SpectralFitting.modelkindMethod
modelkind(M::Type{<:AbstractSpectralModel})
-modelkind(::AbstractSpectralModel)

Return the kind of model given by M: either Additive, Multiplicative, or Convolutional.

source
SpectralFitting.numbertypeMethod
numbertype(::AbstractSpectralModel)

Get the numerical type of the model. This goes through FitParam, so that the number type returned is as close to a primative as possible.

See also paramtype.

Example

numbertype(PowerLaw()) == Float64
source
SpectralFitting.objective_transformerMethod
objective_transformer(layout::AbstractLayout, dataset::AbstractDataset)

Used to transform the output of the model onto the output domain. For spectral fitting, this is the method used to do response folding and bin masking.

If none provided, uses the _DEFAULT_TRANSFORMER

function _DEFAULT_TRANSFORMER()
+)

Creates and optimizes a surrogate model of type S for model, using wrap_model_as_objective and optimize_accuracy! for optimization_samples iterations. Model is initially seeded with seed_samples points prior to optimization.

Warning

Additive models integrate energies to calculate flux, which surrogate models are currently not capable of. Results for Additive models likely to be inaccurate. This will be patched in a future version.

source
SpectralFitting.modelkindMethod
modelkind(M::Type{<:AbstractSpectralModel})
+modelkind(::AbstractSpectralModel)

Return the kind of model given by M: either Additive, Multiplicative, or Convolutional.

source
SpectralFitting.numbertypeMethod
numbertype(::AbstractSpectralModel)

Get the numerical type of the model. This goes through FitParam, so that the number type returned is as close to a primative as possible.

See also paramtype.

Example

numbertype(PowerLaw()) == Float64
source
SpectralFitting.objective_transformerMethod
objective_transformer(layout::AbstractLayout, dataset::AbstractDataset)

Used to transform the output of the model onto the output domain. For spectral fitting, this is the method used to do response folding and bin masking.

If none provided, uses the _DEFAULT_TRANSFORMER

function _DEFAULT_TRANSFORMER()
     function _transformer!!(domain, objective)
         objective
     end
@@ -41,8 +41,8 @@
         @. output = objective
     end
     _transformer!!
-end
source
SpectralFitting.optimize_accuracy!Method
optimize_accuracy!(
     surr::AbstractSurrogate,
     obj::Function,
     lb,
@@ -51,16 +51,16 @@
     maxiters = 200,
     N_truth = 5000,
     verbose = false,
-)

Improve accuracy (faithfullness) of the surrogate model in recreating the objective function.

Samples a new space of N_truth points between lb and ub, and calculates the objective function obj at each. Finds the point with largest MSE between surrogate and objective, and adds the point to the surrogate pool. Repeats maxiters times, adding maxiters points to surrogate model.

Optionally print to stdout the MSE and iteration count with verbose = true.

Note that upper- and lower-bounds should be in the form (E, params...), where E is a single energy and params are the model parameters.

source
SpectralFitting.preferred_supportMethod
preferred_support(x)

Get the preferred AbstractLayout of x. If multiple supports are available, the DEFAULT_SUPPORT_ORDERING is followed:

DEFAULT_SUPPORT_ORDERING = (ContiguouslyBinned{Nothing}(nothing), OneToOne{Nothing}(nothing))
source
SpectralFitting.preferred_unitsMethod
preferred_units(::Type{<:AbstractDataset}, s::AbstractStatistic)
-preferred_units(x, s::AbstractStatistic)

Get the preferred units that a given dataset would use to fit the AbstractStatistic in. For example, for ChiSquared, the units of the model may be a rate, however for Cash the preferred units might be counts.

Returning nothing from this function implies there is no unit preference.

If undefined for a derived type, returns nothing.

See also support_units.

source
SpectralFitting.register_model_dataMethod
SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, model_data::ModelDataInfo...)
+)

Improve accuracy (faithfullness) of the surrogate model in recreating the objective function.

Samples a new space of N_truth points between lb and ub, and calculates the objective function obj at each. Finds the point with largest MSE between surrogate and objective, and adds the point to the surrogate pool. Repeats maxiters times, adding maxiters points to surrogate model.

Optionally print to stdout the MSE and iteration count with verbose = true.

Note that upper- and lower-bounds should be in the form (E, params...), where E is a single energy and params are the model parameters.

source
SpectralFitting.preferred_supportMethod
preferred_support(x)

Get the preferred AbstractLayout of x. If multiple supports are available, the DEFAULT_SUPPORT_ORDERING is followed:

DEFAULT_SUPPORT_ORDERING = (ContiguouslyBinned{Nothing}(nothing), OneToOne{Nothing}(nothing))
source
SpectralFitting.preferred_unitsMethod
preferred_units(::Type{<:AbstractDataset}, s::AbstractStatistic)
+preferred_units(x, s::AbstractStatistic)

Get the preferred units that a given dataset would use to fit the AbstractStatistic in. For example, for ChiSquared, the units of the model may be a rate, however for Cash the preferred units might be counts.

Returning nothing from this function implies there is no unit preference.

If undefined for a derived type, returns nothing.

See also support_units.

source
SpectralFitting.register_model_dataMethod
SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, model_data::ModelDataInfo...)
 SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, remote_and_local::Tuple{String,String}...)
 SpectralFitting.register_model_data(M::Type{<:AbstractSpectralModel}, filenames::String...)
 SpectralFitting.register_model_data(s::Symbol, filenames::String...)

Register filenames as model data associated with the model given by type M or symbol s. This function does not download any files, but rather adds the relevant filenames to a lookup which SpectralFitting.download_model_data consults when invoked, and consequently model data is only downloaded when needed.

Note

It is good practice to use this method immediately after defining a new model with @xspecmodel to register any required datafiles from the HEASoft source code, and therefore keep relevant information together.

Example

# by type
 register_model_data(XS_Laor, "ari.mod")
 # by symbol
-register_model_data(:XS_KyrLine, "KBHline01.fits")
source
SpectralFitting.response_energyMethod
response_energy(response::ResponseMatrix)

Get the contiguously binned energy corresponding to the input domain of the response matrix. This is equivalent to the model domain.

source
SpectralFitting.support_unitsMethod
support_units(x)

Return the units of a particular layout. If this method returns nothing, assume the layout does not care about the units and handle that information appropriately (throw an error or set defaults).

source
SpectralFitting.supportsMethod
supports(x::Type)

Used to define whether a given type has support for a specific AbstractLayout. Should return a tuple of the supported layouts. This method should be implemented to express new support, not the query method.

To query, there is

supports(layout::AbstractLayout, x)::Bool

Example

supports(::Type{typeof(x)}) = (OneToOne(),)
-@assert supports(ContiguouslyBinned(), x) == false
source
SpectralFitting.wrap_model_as_objectiveMethod
wrap_model_as_objective(model::AbstractSpectralModel; ΔE = 1e-1)
-wrap_model_as_objective(M::Type{<:AbstractSpectralModel}; ΔE = 1e-1)

Wrap a spectral model into an objective function for building/optimizing a surrogate model. Returns an anonymous function taking the tuple (E, params...) as the argument, and returning a single flux value.

source
SpectralFitting.AbstractSpectralModelImplementationType
abstract type AbstractSpectralModelImplementation end

Details about the implementation are represented by this abstract type, used in the trait pattern. Concrete types are

  • JuliaImplementation(): means the model is implemented in the Julia programming language.
  • XSPECImplementation(): means the model is vendored from the XSPEC model library.
source
SpectralFitting.AbstractTableModelType
abstract type AbstractTableModel{T,K} <: AbstractSpectralModel{T,K} end

Abstract type representing table models, i.e. those models that interpolate or load data from a table.

First field in the struct must be table. See PhotoelectricAbsorption for an example implementation.

source
SpectralFitting.XS_CutOffPowerLawType
XS_CutOffPowerLaw(K, Γ, Ecut, z)
  • K: Normalisation.

  • Γ: Photon index.

  • Ecut: Cut-off energy (keV).

  • z: Redshift.

Example

using SpectralFitting
+register_model_data(:XS_KyrLine, "KBHline01.fits")
source
SpectralFitting.response_energyMethod
response_energy(response::ResponseMatrix)

Get the contiguously binned energy corresponding to the input domain of the response matrix. This is equivalent to the model domain.

source
SpectralFitting.support_unitsMethod
support_units(x)

Return the units of a particular layout. If this method returns nothing, assume the layout does not care about the units and handle that information appropriately (throw an error or set defaults).

source
SpectralFitting.supportsMethod
supports(x::Type)

Used to define whether a given type has support for a specific AbstractLayout. Should return a tuple of the supported layouts. This method should be implemented to express new support, not the query method.

To query, there is

supports(layout::AbstractLayout, x)::Bool

Example

supports(::Type{typeof(x)}) = (OneToOne(),)
+@assert supports(ContiguouslyBinned(), x) == false
source
SpectralFitting.wrap_model_as_objectiveMethod
wrap_model_as_objective(model::AbstractSpectralModel; ΔE = 1e-1)
+wrap_model_as_objective(M::Type{<:AbstractSpectralModel}; ΔE = 1e-1)

Wrap a spectral model into an objective function for building/optimizing a surrogate model. Returns an anonymous function taking the tuple (E, params...) as the argument, and returning a single flux value.

source
SpectralFitting.AbstractSpectralModelImplementationType
abstract type AbstractSpectralModelImplementation end

Details about the implementation are represented by this abstract type, used in the trait pattern. Concrete types are

  • JuliaImplementation(): means the model is implemented in the Julia programming language.
  • XSPECImplementation(): means the model is vendored from the XSPEC model library.
source
SpectralFitting.AbstractTableModelType
abstract type AbstractTableModel{T,K} <: AbstractSpectralModel{T,K} end

Abstract type representing table models, i.e. those models that interpolate or load data from a table.

First field in the struct must be table. See PhotoelectricAbsorption for an example implementation.

source
SpectralFitting.XS_CutOffPowerLawType
XS_CutOffPowerLaw(K, Γ, Ecut, z)
  • K: Normalisation.

  • Γ: Photon index.

  • Ecut: Cut-off energy (keV).

  • z: Redshift.

Example

using SpectralFitting
 using UnicodePlots
 energy = 10 .^collect(range(-1.0, 2.0, 100))
 m = invokemodel(energy, XS_CutOffPowerLaw())
@@ -83,7 +83,7 @@
 10⁻⁶    │                                       :│ 
         └────────────────────────────────────────┘ 
          10⁻¹                                 10²  
-                        Energy (keV)
source
SpectralFitting.XS_JetType
XS_Jet(K, mass, Dco, log_mdot, thetaobs, BulkG, phi, zdiss, B, logPrel, gmin_inj, gbreak, gmax, s1, s2, z)
  • K: MUST BE FIXED AT UNITY as the jet spectrum normalisation is set by the relativisitic particle power.

  • mass: Black hole mass in solar masses.

  • Dco: Comoving (proper) distance in Mpc.

  • log_mdot: log(L/L_Edd.

  • thetaobs: Inclination angle (deg).

  • BulkG: Bulk lorentz factor of the jet.

  • phi: Angular size scale (radians) of the jet acceleration region as seen from the black hole.

  • zdiss: Vertical distance from the black hole of the jet dissipation region (r_g).

  • B: Magnetic field in the jet (Gauss).

  • logPrel: Log of the power injected in relativisitic particles (ergs/s).

  • gmin_inj: Minimum lorentz factor of the injected electrons.

  • gbreak: Lorentz factor of the break in injected electron distribution.

  • gmax: Maximum lorentz factor.

  • s1: Injected index of the electron distribution below the break.

  • s2: Injected index of the electron distribution above the break.

  • z: Cosmological redshift corresponding to the comoving distance used above.

Example

using UnicodePlots
+                        Energy (keV)
source
SpectralFitting.XS_JetType
XS_Jet(K, mass, Dco, log_mdot, thetaobs, BulkG, phi, zdiss, B, logPrel, gmin_inj, gbreak, gmax, s1, s2, z)
  • K: MUST BE FIXED AT UNITY as the jet spectrum normalisation is set by the relativisitic particle power.

  • mass: Black hole mass in solar masses.

  • Dco: Comoving (proper) distance in Mpc.

  • log_mdot: log(L/L_Edd.

  • thetaobs: Inclination angle (deg).

  • BulkG: Bulk lorentz factor of the jet.

  • phi: Angular size scale (radians) of the jet acceleration region as seen from the black hole.

  • zdiss: Vertical distance from the black hole of the jet dissipation region (r_g).

  • B: Magnetic field in the jet (Gauss).

  • logPrel: Log of the power injected in relativisitic particles (ergs/s).

  • gmin_inj: Minimum lorentz factor of the injected electrons.

  • gbreak: Lorentz factor of the break in injected electron distribution.

  • gmax: Maximum lorentz factor.

  • s1: Injected index of the electron distribution below the break.

  • s2: Injected index of the electron distribution above the break.

  • z: Cosmological redshift corresponding to the comoving distance used above.

Example

using UnicodePlots
 energy = 10 .^collect(range(-8.0, 8.0, 100))
 m = invokemodel(energy, XS_Jet())
 lineplot(energy[1:end-1],m,xscale=:log10,yscale=:log10,xlim=(1e-8,1e8),ylim=(1e-8,1e8),xlabel="Energy (keV)",ylabel="Flux",title="XS_Jet",canvas=DotCanvas)
                        XS_Jet                   
@@ -105,7 +105,7 @@
 10⁻⁸    │                                 ''.    │ 
         └────────────────────────────────────────┘ 
         10⁻⁸                                 10⁸  
-                        Energy (keV)                
source
SpectralFitting.Reflection.add_objective_reduction!Method
add_objective_reduction!(ra::CompositeAggregation, op::Symbol)

Reduces the current objective count and applies the reduction operation op to them. For example, if op is :+, and the objective count is 3, then after this function has been called the objective count will be 2 and the reduction expression

@. flux2 = flux2 + flux3

will have been added to the CompositeAggregation.

source
SpectralFitting.Reflection.assemble_objective_unpackMethod
assemble_objective_unpack(N)

Assembles the statements for unpacking the objective cache into a number of views. Assembles the part of the model call that looks like:

objective1 = view(objectives, :, 1), objective2 = ...

for N objectives slices.

source
SpectralFitting.Reflection.make_constructorMethod
make_constructor(model::Type{<:AbstractSpectralModel}, closures::Vector, params::Vector, T::Type)

Create a constructor expression for the model. Should return something similar to

:(PowerLaw{T}(arg1, arg2, arg3)))

unpacking the closures and params vectors in the appropriate places.

source
SpectralFitting.Reflection.add_objective_reduction!Method
add_objective_reduction!(ra::CompositeAggregation, op::Symbol)

Reduces the current objective count and applies the reduction operation op to them. For example, if op is :+, and the objective count is 3, then after this function has been called the objective count will be 2 and the reduction expression

@. flux2 = flux2 + flux3

will have been added to the CompositeAggregation.

source
SpectralFitting.Reflection.assemble_objective_unpackMethod
assemble_objective_unpack(N)

Assembles the statements for unpacking the objective cache into a number of views. Assembles the part of the model call that looks like:

objective1 = view(objectives, :, 1), objective2 = ...

for N objectives slices.

source
SpectralFitting.Reflection.make_constructorMethod
make_constructor(model::Type{<:AbstractSpectralModel}, closures::Vector, params::Vector, T::Type)

Create a constructor expression for the model. Should return something similar to

:(PowerLaw{T}(arg1, arg2, arg3)))

unpacking the closures and params vectors in the appropriate places.

source
SpectralFitting.Reflection.CompositeModelInfoType
struct CompositeModelInfo
     "The parameter symbols of the model with the respective lens to the actual parameter."
     parameter_symbols::Vector{Pair{Symbol,Lens}}
     "Each model assigned to a unique symbol."
@@ -118,7 +118,7 @@
     maximum_objective_cache_count::Int
     "How many objective caches are currently active."
     objective_cache_count::Int
-end

The composite equivalent of ModelInfo, augmented to track the model symbol (a1, m3, etc.), and the model parameters (K_1, a_3, etc.)

source
SpectralFitting.Reflection.ModelInfoType
struct ModelInfo
     "All parameter symbols for the model."
     symbols::Vector{Symbol}
     "Unique symbols generated for the parameter assignment when buildin the function call."
@@ -131,4 +131,4 @@
     lens::Lens
     "The model type itself."
     model::Type
-end

All models are parsed into a ModelInfo struct relative to their parent (in the case of composite models).

The symbols field contains all of the model parameter symbols as they are in the structure, not as they have been generated. Recall when the invocation expressions are generated, we create anonymous paramter names to avoid conflicts. These are the generated_symbols instead.

source
+end

All models are parsed into a ModelInfo struct relative to their parent (in the case of composite models).

The symbols field contains all of the model parameter symbols as they are in the structure, not as they have been generated. Recall when the invocation expressions are generated, we create anonymous paramter names to avoid conflicts. These are the generated_symbols instead.

source
diff --git a/dev/transitioning-from-xspec/index.html b/dev/transitioning-from-xspec/index.html index 55dd2a0a..1f12cb4c 100644 --- a/dev/transitioning-from-xspec/index.html +++ b/dev/transitioning-from-xspec/index.html @@ -1,2 +1,2 @@ -Transitioning from XSPEC · SpectralFitting.jl
+Transitioning from XSPEC · SpectralFitting.jl
diff --git a/dev/walkthrough/62e0bb86.svg b/dev/walkthrough/3bacab51.svg similarity index 70% rename from dev/walkthrough/62e0bb86.svg rename to dev/walkthrough/3bacab51.svg index 38d00446..1c53b72e 100644 --- a/dev/walkthrough/62e0bb86.svg +++ b/dev/walkthrough/3bacab51.svg @@ -1,397 +1,397 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/3d287d54.svg b/dev/walkthrough/3bfbd42e.svg similarity index 83% rename from dev/walkthrough/3d287d54.svg rename to dev/walkthrough/3bfbd42e.svg index 79856966..58084219 100644 --- a/dev/walkthrough/3d287d54.svg +++ b/dev/walkthrough/3bfbd42e.svg @@ -1,54 +1,54 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/2c8c3c6e.svg b/dev/walkthrough/3eb0b222.svg similarity index 72% rename from dev/walkthrough/2c8c3c6e.svg rename to dev/walkthrough/3eb0b222.svg index c42c1d42..7db0650d 100644 --- a/dev/walkthrough/2c8c3c6e.svg +++ b/dev/walkthrough/3eb0b222.svg @@ -1,399 +1,399 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/9f9250ae.svg b/dev/walkthrough/405674fe.svg similarity index 70% rename from dev/walkthrough/9f9250ae.svg rename to dev/walkthrough/405674fe.svg index 4f37d0cd..e6734ebd 100644 --- a/dev/walkthrough/9f9250ae.svg +++ b/dev/walkthrough/405674fe.svg @@ -1,397 +1,397 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/cd7c9177.svg b/dev/walkthrough/5b23ff29.svg similarity index 70% rename from dev/walkthrough/cd7c9177.svg rename to dev/walkthrough/5b23ff29.svg index 50599fdc..d49ab77b 100644 --- a/dev/walkthrough/cd7c9177.svg +++ b/dev/walkthrough/5b23ff29.svg @@ -1,401 +1,401 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/543dc105.svg b/dev/walkthrough/918384d8.svg similarity index 67% rename from dev/walkthrough/543dc105.svg rename to dev/walkthrough/918384d8.svg index 93b04c32..1eff874e 100644 --- a/dev/walkthrough/543dc105.svg +++ b/dev/walkthrough/918384d8.svg @@ -1,527 +1,527 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/c90fd845.svg b/dev/walkthrough/92ccfad8.svg similarity index 69% rename from dev/walkthrough/c90fd845.svg rename to dev/walkthrough/92ccfad8.svg index 4a28da76..6e6dcfd9 100644 --- a/dev/walkthrough/c90fd845.svg +++ b/dev/walkthrough/92ccfad8.svg @@ -1,529 +1,529 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/813a997c.svg b/dev/walkthrough/9c0f363c.svg similarity index 77% rename from dev/walkthrough/813a997c.svg rename to dev/walkthrough/9c0f363c.svg index db4092cb..6b98bff7 100644 --- a/dev/walkthrough/813a997c.svg +++ b/dev/walkthrough/9c0f363c.svg @@ -1,373 +1,373 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/a867f9bc.svg b/dev/walkthrough/a8172bc8.svg similarity index 93% rename from dev/walkthrough/a867f9bc.svg rename to dev/walkthrough/a8172bc8.svg index bad7aa2b..714deeef 100644 --- a/dev/walkthrough/a867f9bc.svg +++ b/dev/walkthrough/a8172bc8.svg @@ -1,204 +1,204 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/63f94449.svg b/dev/walkthrough/c5450c79.svg similarity index 71% rename from dev/walkthrough/63f94449.svg rename to dev/walkthrough/c5450c79.svg index 4c53a133..f94a3c01 100644 --- a/dev/walkthrough/63f94449.svg +++ b/dev/walkthrough/c5450c79.svg @@ -1,399 +1,399 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/29a69dfd.svg b/dev/walkthrough/dcfd6e37.svg similarity index 64% rename from dev/walkthrough/29a69dfd.svg rename to dev/walkthrough/dcfd6e37.svg index c5515add..be813edb 100644 --- a/dev/walkthrough/29a69dfd.svg +++ b/dev/walkthrough/dcfd6e37.svg @@ -1,976 +1,976 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/e07e5e40.svg b/dev/walkthrough/e18f3382.svg similarity index 74% rename from dev/walkthrough/e07e5e40.svg rename to dev/walkthrough/e18f3382.svg index ac7c86af..4bbe425e 100644 --- a/dev/walkthrough/e07e5e40.svg +++ b/dev/walkthrough/e18f3382.svg @@ -1,521 +1,521 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/22376bb2.svg b/dev/walkthrough/ef33067c.svg similarity index 73% rename from dev/walkthrough/22376bb2.svg rename to dev/walkthrough/ef33067c.svg index 2d25e365..31adcb85 100644 --- a/dev/walkthrough/22376bb2.svg +++ b/dev/walkthrough/ef33067c.svg @@ -1,401 +1,401 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/1835cdbf.svg b/dev/walkthrough/f00c5c7c.svg similarity index 81% rename from dev/walkthrough/1835cdbf.svg rename to dev/walkthrough/f00c5c7c.svg index 160fec42..7ef2938d 100644 --- a/dev/walkthrough/1835cdbf.svg +++ b/dev/walkthrough/f00c5c7c.svg @@ -1,81 +1,81 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/walkthrough/index.html b/dev/walkthrough/index.html index dca81833..41f9c221 100644 --- a/dev/walkthrough/index.html +++ b/dev/walkthrough/index.html @@ -31,9 +31,9 @@ . Response : /home/runner/work/SpectralFitting.jl/SpectralFitting.jl/docs/build/../../ex-datadir/s54405.rsp . Background : nothing . Ancillary : nothing -

We can load and alter any part of a dataset as we do our fitting. For example, if you have multiple different ancillary files at hand, switching them between fits is a one-liner.

To visualize our data, we can use some of the Plots.jl recipes included in SpectralFitting.jl:

plot(data, xlims = (0.5, 70), xscale = :log10)
Example block output

Note that the units are currently not divided by the energy bin widths. We can either do that manually, or use the normalize! to convert whatever units the data is currently in to the defacto standard counts s⁻¹ keV⁻¹ for fitting. Whilst we're at it, we see in the model card that there are 40 bad quality bins still present in our data. We can drop those as well, and plot the data on log-log axes:

normalize!(data)
+

We can load and alter any part of a dataset as we do our fitting. For example, if you have multiple different ancillary files at hand, switching them between fits is a one-liner.

To visualize our data, we can use some of the Plots.jl recipes included in SpectralFitting.jl:

plot(data, xlims = (0.5, 70), xscale = :log10)
Example block output

Note that the units are currently not divided by the energy bin widths. We can either do that manually, or use the normalize! to convert whatever units the data is currently in to the defacto standard counts s⁻¹ keV⁻¹ for fitting. Whilst we're at it, we see in the model card that there are 40 bad quality bins still present in our data. We can drop those as well, and plot the data on log-log axes:

normalize!(data)
 drop_bad_channels!(data)
-plot(data, ylims = (0.001, 2.0), yscale = :log10, xscale = :log10)
Example block output

Note that when there are no negative axes, the scale defaults to log on the plot unless otherwise specified.

Next we want to specify a model to fit to this data. Models that are prefixed with XS_ are models that are linked from the XSPEC model library, provided via LibXSPEC_jll. For a full list of the models, see Models library.

Warning

It is advised to use the Julia implemented models. This allows various calculations to benefit from automatic differentiation, efficient multi-threading, GPU offloading, and various other useful things, see Why & how.

We will start by fitting a photoelectric absorption model that acts on a power law model:

Note

To see information about a model, use the ? in the Julia REPL:

julia> ?PowerLaw
+plot(data, ylims = (0.001, 2.0), yscale = :log10, xscale = :log10)
Example block output

Note that when there are no negative axes, the scale defaults to log on the plot unless otherwise specified.

Next we want to specify a model to fit to this data. Models that are prefixed with XS_ are models that are linked from the XSPEC model library, provided via LibXSPEC_jll. For a full list of the models, see Models library.

Warning

It is advised to use the Julia implemented models. This allows various calculations to benefit from automatic differentiation, efficient multi-threading, GPU offloading, and various other useful things, see Why & how.

We will start by fitting a photoelectric absorption model that acts on a power law model:

Note

To see information about a model, use the ? in the Julia REPL:

julia> ?PowerLaw
 XS_PowerLaw(K, a)
 
     •  K: Normalisation.
@@ -73,7 +73,7 @@
     xscale = :log10,
     yscale = :log10
 )
-plot!(result)
Example block output

Our model does not account for the high energy range well. We can ignore that range for now, and select everything from 0 to 15 keV and refit:

mask_energies!(data, 0, 15)
+plot!(result)
Example block output

Our model does not account for the high energy range well. We can ignore that range for now, and select everything from 0 to 15 keV and refit:

mask_energies!(data, 0, 15)
 result = fit(prob, LevenbergMarquadt())
┌ FittingResult:
 │   Model: CompositeModel[PhotoelectricAbsorption * PowerLaw]
 │   . u     : [21.584, 2.2307, 0.53199]
@@ -84,7 +84,7 @@
     xscale = :log10,
     yscale = :log10
 )
-plot!(result, label = "PowerLaw")
Example block output

The result is not yet baked into our model, and represents just the outcome of the fit. To update the parameters and errors in the model, we can use update_model!

update_model!(model, result)
┌ CompositeModel with 2 model components:
+plot!(result, label = "PowerLaw")
Example block output

The result is not yet baked into our model, and represents just the outcome of the fit. To update the parameters and errors in the model, we can use update_model!

update_model!(model, result)
┌ CompositeModel with 2 model components:
 │      m1 * a1
 │ Model key and parameters:
 │    a1 => PowerLaw
@@ -94,7 +94,7 @@
 │      ηH_1 ->  0.532 ± 0.1  ∈ [ 0, Inf ]   FREE
Note

Since fitting and updating a model is often done in tandem, SpectralFitting.jl has both a fit and fit! method, the latter automatically updates the model parameters after fit.

To estimate the goodness of our fit, we can mimic the goodness command from XSPEC. This will use the simulate function to simulate spectra for a dataset (here determined by the result), and fit the model to the simulated dataset. The fit statistic for each fit is then appended to an array, which we can use to plot a histogram:

spread = goodness(result; N = 1000, seed = 42, exposure_time = data.data.spectrum.exposure_time)
 histogram(spread, ylims = (0, 300), label = "Simulated")
-vline!([result.χ2], label = "Best fit")
Example block output

Note we have set the random number generator seed with seed = 42 to allow our results to be strictly reproduced.

The goodness command will log the percent of simulations with a fit statistic better than the result, but we can equivalently calculate that ourselves:

count(<(result.χ2), spread) * 100 / length(spread)
56.9

Next we want to calculate the flux in an energy range observed by the detector. We can do this with LogFlux or XS_CalculateFlux, as they are both equivalent implementations.

We can modify our model by accessing properties from the model card and writing a new expression:

calc_flux = XS_CalculateFlux(
+vline!([result.χ2], label = "Best fit")
Example block output

Note we have set the random number generator seed with seed = 42 to allow our results to be strictly reproduced.

The goodness command will log the percent of simulations with a fit statistic better than the result, but we can equivalently calculate that ourselves:

count(<(result.χ2), spread) * 100 / length(spread)
56.9

Next we want to calculate the flux in an energy range observed by the detector. We can do this with LogFlux or XS_CalculateFlux, as they are both equivalent implementations.

We can modify our model by accessing properties from the model card and writing a new expression:

calc_flux = XS_CalculateFlux(
     E_min = FitParam(0.2, frozen = true),
     E_max = FitParam(2.0, frozen = true),
     log10Flux = FitParam(-10.3, lower_limit = -100, upper_limit = 100),
@@ -139,7 +139,7 @@
     yscale = :log10
 )
 plot!(flux_result)
-vspan!([flux_model.c1.E_min.value, flux_model.c1.E_max.value], alpha = 0.5)
Example block output

Let's try alternative models to see how they fit the data. First, an absorbed black body:

model2 = PhotoelectricAbsorption() * XS_BlackBody()
┌ CompositeModel with 2 model components:
+vspan!([flux_model.c1.E_min.value, flux_model.c1.E_max.value], alpha = 0.5)
Example block output

Let's try alternative models to see how they fit the data. First, an absorbed black body:

model2 = PhotoelectricAbsorption() * XS_BlackBody()
┌ CompositeModel with 2 model components:
 │      m1 * a1
 │ Model key and parameters:
 │    a1 => XS_BlackBody
@@ -160,14 +160,14 @@
     legend = :bottomleft,
 )
 plot!(dp, result, label = "PowerLaw $(round(result.χ2))")
-plot!(dp, result2, label = "BlackBody $(round(result2.χ2))")
Example block output

Or a bremsstrahlung model:

model3 = PhotoelectricAbsorption() * XS_BremsStrahlung()
+plot!(dp, result2, label = "BlackBody $(round(result2.χ2))")
Example block output

Or a bremsstrahlung model:

model3 = PhotoelectricAbsorption() * XS_BremsStrahlung()
 prob3 = FittingProblem(model3 => data)
 result3 = fit(prob3, LevenbergMarquadt())
┌ FittingResult:
 │   Model: CompositeModel[PhotoelectricAbsorption * XS_BremsStrahlung]
 │   . u     : [13.868, 5.3034, 0.0]
 │   . σᵤ    : [1.3178, 0.70705, 0.19664]
 │   . χ²    : 40.027 
-└ 
plot!(dp, result3, label = "Brems $(round(result3.χ2))")
Example block output

Let's take a look at the residuals of these three models. There are utility methods for this in SpectralFitting.jl, but we can easily just interact with the result directly:

function calc_residuals(result)
+└ 
plot!(dp, result3, label = "Brems $(round(result3.χ2))")
Example block output

Let's take a look at the residuals of these three models. There are utility methods for this in SpectralFitting.jl, but we can easily just interact with the result directly:

function calc_residuals(result)
     # select which result we want (only have one, but for generalisation to multi-model fits)
     r = result[1]
     y = invoke_result(r)
@@ -180,14 +180,14 @@
 plot!(rp,domain, calc_residuals(result), seriestype = :stepmid)
 plot!(rp, domain, calc_residuals(result2), seriestype = :stepmid)
 plot!(rp, domain, calc_residuals(result3), seriestype = :stepmid)
-rp
Example block output

We can compose this figure with our previous one, and change to a linear x scale:

plot(dp, rp, layout = grid(2, 1, heights = [0.7, 0.3]), link = :x, xscale = :linear)
Example block output

We can do all that plotting work in one go with the plotresult recipe:

plotresult(
+rp
Example block output

We can compose this figure with our previous one, and change to a linear x scale:

plot(dp, rp, layout = grid(2, 1, heights = [0.7, 0.3]), link = :x, xscale = :linear)
Example block output

We can do all that plotting work in one go with the plotresult recipe:

plotresult(
     data,
     [result, result2, result3],
     ylims = (0.001, 2.0),
     xscale = :log10,
     yscale = :log10,
     legend = :bottomleft,
-)
Example block output

Let's modify the black body model with a continuum component

bbpl_model = model2.m1 * (PowerLaw() + model2.a1) |> deepcopy
┌ CompositeModel with 3 model components:
+)
Example block output

Let's modify the black body model with a continuum component

bbpl_model = model2.m1 * (PowerLaw() + model2.a1) |> deepcopy
┌ CompositeModel with 3 model components:
 │      m1 * (a2 + a1)
 │ Model key and parameters:
 │    a1 => XS_BlackBody
@@ -225,7 +225,7 @@
     yscale = :log10,
     legend = :bottomleft,
 )
-plot!(bbpl_result)
Example block output

Update the model and fix the black body temperature to 2 keV:

update_model!(bbpl_model, bbpl_result)
+plot!(bbpl_result)
Example block output

Update the model and fix the black body temperature to 2 keV:

update_model!(bbpl_model, bbpl_result)
 
 bbpl_model.T_1.value = 2.0
 bbpl_model.T_1.frozen = true
@@ -248,7 +248,7 @@
 │   . u     : [0.38234, 573.17, 4.8351]
 │   . σᵤ    : [0.034796, 83.183, 0.16012]
 │   . χ²    : 71.708 
-└ 

Overplotting this new result:

plot!(bbpl_result2)
Example block output

MCMC

We can use libraries like Pidgeons.jl or Turing.jl to perform Bayesian inference on our paramters. SpectralFitting.jl is designed with BYOO (Bring Your Own Optimizer) in mind, and so makes it relatively easy to get at the core fitting functions to be used with other packages.

Let's use Turing.jl here, which means we'll also want to use StatsPlots.jl to plot our walker chains.

using StatsPlots
+└ 

Overplotting this new result:

plot!(bbpl_result2)
Example block output

MCMC

We can use libraries like Pidgeons.jl or Turing.jl to perform Bayesian inference on our paramters. SpectralFitting.jl is designed with BYOO (Bring Your Own Optimizer) in mind, and so makes it relatively easy to get at the core fitting functions to be used with other packages.

Let's use Turing.jl here, which means we'll also want to use StatsPlots.jl to plot our walker chains.

using StatsPlots
 using Turing

Turing.jl provides enormous control over the definition of the model, and this is not control SpectralFitting.jl wants to take away from you. Although we will provide utility scripts to do the basics, here we'll show you everything step by step to give you an overview of what you can do.

Let's go back to our first model:

model
┌ CompositeModel with 2 model components:
 │      m1 * a1
 │ Model key and parameters:
@@ -276,8 +276,8 @@
 Iterations        = 1001:1:6000
 Number of chains  = 1
 Samples per chain = 5000
-Wall duration     = 14.23 seconds
-Compute duration  = 14.23 seconds
+Wall duration     = 14.68 seconds
+Compute duration  = 14.68 seconds
 parameters        = K, a, ηH
 internals         = lp, n_steps, is_accept, acceptance_rate, log_density, hamiltonian_energy, hamiltonian_energy_error, max_hamiltonian_energy_error, tree_depth, numerical_error, step_size, nom_step_size
 
@@ -297,4 +297,4 @@
            K   18.6898   19.6935   20.2662   20.8458   21.9474
            a    2.1239    2.1650    2.1877    2.2106    2.2530
           ηH    0.3310    0.4201    0.4708    0.5198    0.6214
-

In the printout we see summary statistics about or model, in this case that it has converged well (rhat close to 1 for all parameters), better estimates of the standard deviation, and various quantiles. We can plot our chains to make sure the caterpillers are healthy and fuzzy, making use of StatsPlots.jl recipes:

plot(chain)
Example block output

Corner plots are currently broken at time of writing.

+

In the printout we see summary statistics about or model, in this case that it has converged well (rhat close to 1 for all parameters), better estimates of the standard deviation, and various quantiles. We can plot our chains to make sure the caterpillers are healthy and fuzzy, making use of StatsPlots.jl recipes:

plot(chain)
Example block output

Corner plots are currently broken at time of writing.

diff --git a/dev/why-and-how/index.html b/dev/why-and-how/index.html index 701a56fe..d1181a4a 100644 --- a/dev/why-and-how/index.html +++ b/dev/why-and-how/index.html @@ -59,4 +59,4 @@ return objective1 end end -end

This generated function also takes care of some other things for us, such as unpacking parameters (optionally unpacking frozen parameters separately), and ensuring any closure are passed to invokemodel if a model needs them (e.g., SurrogateSpectralModel).

This is achieved by moving as much information as possible about the model and its construction to its type, such that all of the invocation and parameter unpacking may be inferred at compile time.

Note

With the addition of more pure-Julia models, non-allocating methods without aggressive pre-allocation are possible, and will be added in the future. Such methods may allow models to add or multiply in-place on the total flux array, instead of relying on later broadcasts.

+end

This generated function also takes care of some other things for us, such as unpacking parameters (optionally unpacking frozen parameters separately), and ensuring any closure are passed to invokemodel if a model needs them (e.g., SurrogateSpectralModel).

This is achieved by moving as much information as possible about the model and its construction to its type, such that all of the invocation and parameter unpacking may be inferred at compile time.

Note

With the addition of more pure-Julia models, non-allocating methods without aggressive pre-allocation are possible, and will be added in the future. Such methods may allow models to add or multiply in-place on the total flux array, instead of relying on later broadcasts.