Recipes

QSFit.jl provides the following ready-to-use recipes:

InteractiveLineFit

Interactive emission line fitting. The user is asked to provide the initial guess wavelengths of emission lines by clicking on a plot (provided by the Gnuplot.jl package), as well as to decide the line profile to be used. Example:

using QSFit, QSFit.LineFitRecipes

filename = download("http://dr10.sdss3.org/sas/dr10/sdss/spectro/redux/26/spectra/0752/spec-0752-52251-0323.fits")
spec = Spectrum(Val(:SDSS_DR10), filename)
recipe = Recipe(InteractiveLineFit, redshift=0.3806)
res = analyze(recipe, spec)

After interactive selection the above code will print the relevant options to replicate the same analysis using the LineFit recipe (see below);

LineFit

Non-interactive line fitting. The user should provide the relevant options such as the redshift, the wavelength range, the guess wavelengths of the emission lines, etc. The latter can be obtained using the above mentioned InteractiveLineFit recipe. Example:

using QSFit, QSFit.LineFitRecipes

filename = download("http://dr10.sdss3.org/sas/dr10/sdss/spectro/redux/26/spectra/0752/spec-0752-52251-0323.fits")
spec = Spectrum(Val(:SDSS_DR10), filename)
recipe = Recipe(LineFit, redshift=0.3806)
recipe.wavelength_range = [4610.1157888384, 5130.00163811462]
add_line!(recipe, QSFit.ATL.UnidentifiedTransition(4866.45), NarrowLine,BroadLine)
add_line!(recipe, QSFit.ATL.UnidentifiedTransition(5008.98), ForbiddenLine)
res = analyze(recipe, spec)

Type1

Automatic spectral analysis of Type1 AGN and QSO at redshifts <~ 2.1. Example:

using QSFit, QSFit.QSORecipes
filename = download("http://dr10.sdss3.org/sas/dr10/sdss/spectro/redux/26/spectra/0752/spec-0752-52251-0323.fits")
spec = Spectrum(Val(:SDSS_DR10), filename)
recipe = Recipe(Type1, redshift=0.3806, Av=0.21)
res = analyze(recipe, spec)

Customizing built-in recipes

To be written.

using GModelFit
abstract type MyRecipe <: Type1 end
import QSFit.QSORecipes.add_qso_continuum!
function add_qso_continuum!(recipe::Recipe{T}, resid::GModelFit.Residuals) where T <: MyRecipe
    @invoke add_qso_continuum!(recipe::Recipe{<: supertype(T)}, resid)
    resid.meval.model[:QSOcont].alpha.fixed = true
end
spec = Spectrum(Val(:SDSS_DR10), "spec-0752-52251-0323.fits", label="My SDSS source")
recipe = Recipe(MyRecipe, redshift=0.3806)
res = analyze(recipe, spec)
display(res.bestfit)


using GModelFit, Statistics
function add_qso_continuum!(recipe::Recipe{T}, resid::GModelFit.Residuals) where T <: MyRecipe
    λ = coords(domain(resid.data))
    comp = QSFit.sbpl(3000)
    comp.x0.val = median(λ)
    comp.norm.val = median(values(resid.data))
    comp.norm.low = comp.norm.val / 1000.  # ensure contiuum remains positive (needed to estimate EWs)
    resid.meval.model[:QSOcont] = comp
    push!(resid.meval.model[:Continuum].list, :QSOcont)
    GModelFit.update!(resid.meval)
end
spec = Spectrum(Val(:SDSS_DR10), "spec-0752-52251-0323.fits", label="My SDSS source")
recipe = Recipe(MyRecipe, redshift=0.3806)
res = analyze(recipe, spec)
display(res.bestfit)

Define new recipes

To be written.

using GModelFit, QSFit
import QSFit: init_recipe!, preprocess_spec!, analyze

abstract type MyRecipe <: AbstractRecipeSpec end

function init_recipe!(recipe::Recipe{T}) where T <: MyRecipe
    @invoke init_recipe!(recipe::Recipe{<: AbstractRecipeSpec})
    recipe.wavelength_range = [1215, 7.3e3]
end

function preprocess_spec!(recipe::Recipe{T}, spec::QSFit.Spectrum) where T <: MyRecipe
    @invoke preprocess_spec!(recipe::Recipe{<: AbstractRecipeSpec}, spec)
end

function analyze(recipe::Recipe{T}, spec::QSFit.Spectrum, resid::GModelFit.Residuals) where T <: MyRecipe
    resid.mzer.config.ftol = 1.e-6
    model = resid.meval.model
    return GModelFit.minimize!(resid)
end