Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions R/AGN.R
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,79 @@ SKIRTOR_interp = function(lum = 1e+44, ct = 40, rm = 60, an = 30, ta = 1, p = 1,
return(data.frame(wave=SKIRTOR$Wave, lum = agn_spectrum))

}

Fritz_anav_interp = function(lum = 1e+44, ct = 40, rm = 60, ta = 1, al = 4, be = -0.5,
Fritz_anav = NULL){
if(is.null(Fritz_anav)){
Fritz_anav = NULL
data('Fritz_anav', envir = environment())
Fritz_anav = get('Fritz_anav', envir = environment())
}
if(!inherits(Fritz_anav, 'Fritz_anav')){
stop('Fritz_anav must be a Fritz_anav object.', call. = FALSE)
}

ctmix = interp_quick(ct, Fritz_anav$ct)
almix = interp_quick(al, Fritz_anav$al)
bemix = interp_quick(be, Fritz_anav$be)
tamix = interp_quick(ta, Fritz_anav$ta)
rmmix = interp_quick(rm, Fritz_anav$rm)

slice = Fritz_anav$Aspec[
c(ctmix[1:2]),
c(almix[1:2]),
c(bemix[1:2]),
c(tamix[1:2]),
c(rmmix[1:2]),
]

weights = rep(1,32)
weights = weights * rep(ctmix[3:4], each=1, times=16)
weights = weights * rep(almix[3:4], each=2, times=8)
weights = weights * rep(bemix[3:4], each=4, times=4)
weights = weights * rep(tamix[3:4], each=8, times=2)
weights = weights * rep(rmmix[3:4], each=16, times=1)
tempmat = matrix(as.numeric(slice), 32, length(Fritz_anav$Wave))
return(data.frame(wave = Fritz_anav$Wave, lum = lum * colSums(tempmat * weights)))
}


SKIRTOR_anav_interp = function(lum = 1e+44, ct = 40, rm = 60, ta = 1, p = 1, q = 1,
SKIRTOR_anav = NULL){

if(is.null(SKIRTOR_anav)){
SKIRTOR_anav = NULL
data('SKIRTOR_anav', envir = environment())
SKIRTOR_anav = get('SKIRTOR_anav', envir = environment())
}
if(!inherits(SKIRTOR_anav, 'SKIRTOR_anav')){
stop('SKIRTOR_anav must be a SKIRTOR_anav object.', call. = FALSE)
}

tmix = interp_quick(ta, SKIRTOR_anav$ta)
pmix = interp_quick(p, SKIRTOR_anav$p)
qmix = interp_quick(q, SKIRTOR_anav$q)
oamix = interp_quick(ct, SKIRTOR_anav$ct)
rmmix = interp_quick(rm, SKIRTOR_anav$rm)

slice = SKIRTOR_anav$Aspec[
c(tmix[1:2]),
c(pmix[1:2]),
c(qmix[1:2]),
c(oamix[1:2]),
c(rmmix[1:2]),
1,
]

weights = rep(1,32)
weights = weights * rep(tmix[3:4], each=1, times=16)
weights = weights * rep(pmix[3:4], each=2, times=8)
weights = weights * rep(qmix[3:4], each=4, times=4)
weights = weights * rep(oamix[3:4], each=8, times=2)
weights = weights * rep(rmmix[3:4], each=16, times=1)
tempmat = matrix(as.numeric(slice), 32, length(SKIRTOR_anav$Wave))
agn_spectrum = colSums(tempmat * weights)/SKIRTOR_anav$Wave
agn_spectrum = (agn_spectrum/(3.839e33 * 1E11))*lum
return(data.frame(wave = SKIRTOR_anav$Wave, lum = agn_spectrum))

}
59 changes: 57 additions & 2 deletions R/ProSpect.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,17 @@ ProSpectSED = function(SFH = SFHfunc,
IGMabsorb = 0,
Inoue14_LAFcoef = NULL,
Inoue14_DLAcoef = NULL,
AGN_screen_model = 'viewing_angle',
AGN_anav = NULL,
...) {
#call = match.call()

if (!is.character(AGN_screen_model) || length(AGN_screen_model) != 1L ||
is.na(AGN_screen_model) ||
!AGN_screen_model %in% c('viewing_angle', 'angle_averaged', 'None')) {
stop("AGN_screen_model must be 'viewing_angle', 'angle_averaged', or 'None'.", call. = FALSE)
}

if(!is.null(waveout)){
waveout_max = max(waveout)
}else{
Expand Down Expand Up @@ -173,10 +181,21 @@ ProSpectSED = function(SFH = SFHfunc,
stop('Dale cannot be FALSE when using an AGN model!')
}

if (AGN_screen_model == 'angle_averaged' &&
!inherits(AGN, 'Fritz') && !inherits(AGN, 'SKIRTOR')) {
stop('Angle-averaged AGN emission requires a Fritz or SKIRTOR model')
}

if(inherits(AGN, 'Fritz') |
inherits(AGN, 'SKIRTOR')) {
#Use new model
if (inherits(AGN, 'Fritz')) {
if (AGN_screen_model == 'angle_averaged') {
AGN_mean = Fritz_anav_interp(
lum = AGNlum, ct = AGNct, rm = AGNrm, ta = AGNta,
al = AGNal, be = AGNbe, Fritz_anav = AGN_anav
)
}
AGN = Fritz_interp(
lum = AGNlum,
ct = AGNct,
Expand All @@ -188,6 +207,12 @@ ProSpectSED = function(SFH = SFHfunc,
Fritz = AGN
)
} else if (inherits(AGN, 'SKIRTOR')) {
if (AGN_screen_model == 'angle_averaged') {
AGN_mean = SKIRTOR_anav_interp(
lum = AGNlum, ta = AGNta, p = AGNp, q = AGNq,
ct = AGNct, rm = AGNrm, SKIRTOR_anav = AGN_anav
)
}
AGN = SKIRTOR_interp(
lum = AGNlum,
ta = AGNta,
Expand All @@ -203,10 +228,18 @@ ProSpectSED = function(SFH = SFHfunc,
dustlum_AGN = NA
dustmass_AGN = NA
#Second we re-attenuate the above by the screen (since it still has to pass out of the galaxy)
if (AGN_screen_model == 'angle_averaged') {
direct = CF_screen_atten(
wave = AGN$wave, flux = AGN$lum * .erg_to_lsol,
tau = tau_screen, pow = pow_screen, Eb = Eb, L0 = L0, LFWHM = LFWHM
)
selected = AGN
AGN = AGN_mean
}
AGN = atten_emit(
wave = AGN$wave,
flux = AGN$lum * .erg_to_lsol,
tau = tau_screen,
tau = if (AGN_screen_model == 'None') 0 else tau_screen,
pow = pow_screen,
alpha_SF = alpha_SF_screen,
Dale = Dale,
Expand All @@ -216,6 +249,14 @@ ProSpectSED = function(SFH = SFHfunc,
L0 = L0,
LFWHM = LFWHM
)
if (AGN_screen_model == 'angle_averaged') {
#The sightline sets direct light; the angular mean sets dust heating.
AGN$final = addspec(
wave1 = selected$wave, flux1 = direct$flux,
wave2 = AGN$emit$wave, flux2 = AGN$emit$flux,
extrap = 0, waveout = waveout
)
}
if (!is.null(Dale_M2L_func) & returnall) {
dustlum_screen = dustlum_screen + AGN$total_atten
dustmass_screen = dustmass_screen + AGN$dustmass
Expand Down Expand Up @@ -273,7 +314,7 @@ ProSpectSED = function(SFH = SFHfunc,
AGN = atten_emit(
wave = AGN$final$wave,
flux = AGN$final$flux,
tau = tau_screen,
tau = if (AGN_screen_model == 'None') 0 else tau_screen,
pow = pow_screen,
alpha_SF = alpha_SF_screen,
Dale = Dale,
Expand Down Expand Up @@ -500,6 +541,20 @@ ProSpectSED = function(SFH = SFHfunc,
}

ProSpectSEDlike = function(parm = c(8, 9, 10, 10, 0, -0.5, 0.2), Data) {
if (!is.null(Data$AGN_screen_model)) {
Data$arglist$AGN_screen_model = Data$AGN_screen_model
}
if (!is.null(Data$AGN_anav)) {
Data$arglist$AGN_anav = Data$AGN_anav
}
if (!is.null(Data$arglist$AGN_screen_model) &&
(!is.character(Data$arglist$AGN_screen_model) ||
length(Data$arglist$AGN_screen_model) != 1L ||
is.na(Data$arglist$AGN_screen_model) ||
!Data$arglist$AGN_screen_model %in% c('viewing_angle', 'angle_averaged', 'None'))) {
stop("Data$AGN_screen_model must be 'viewing_angle', 'angle_averaged', or 'None'.", call. = FALSE)
}

if (is.null(Data$fit)) {
Data$fit = 'optim'
}
Expand Down
2 changes: 1 addition & 1 deletion R/plots.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ plot.ProSpectSED = function(x,
if (ylim[1] == 'auto') {
if(!is.null(x$Stars)){
ylim = c(quantile(x$FinalLum[, 2], 0.45),
max(x$StarsUnAtten, na.rm = TRUE))
max(x$StarsUnAtten$lum, na.rm = TRUE))
}else{
ylim = c(quantile(x$FinalLum[, 2], 0.45),
max(x$FinalLum[, 2], na.rm = TRUE))
Expand Down
24 changes: 23 additions & 1 deletion man/AGNinterp.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,31 @@
\alias{AGNinterp}
\alias{Fritz_interp}
\alias{SKIRTOR_interp}
\alias{Fritz_anav_interp}
\alias{SKIRTOR_anav_interp}
%- Also NEED an '\alias' for EACH other topic documented here.
\title{
Interpolate the Fritz (2006) and SKIRTOR (2016) AGN Templates
}
\description{
Interpolates between non-computed values of the Fritz 2006 AGN Templates using a mixture of schemes. This is similar to the approach used for \code{\link{Dale_interp}}. The model is much too complex to summarise here, so interested readers should refer to the source papers if using this function for science.

\code{Fritz_anav_interp} and \code{SKIRTOR_anav_interp} interpolate the
angle-averaged template libraries. They have no viewing-angle argument and
retain the luminosity normalisation of the corresponding viewing-angle models.
}
\usage{
Fritz_interp(lum = 1e+44, ct = 40, rm = 60, an = 30, ta = 1, al = 4, be = -0.5,
Fritz = NULL)

SKIRTOR_interp(lum = 1e+44, ct = 40, rm = 60, an = 30, ta = 1, p = 1, q = 1,
SKIRTOR = NULL)

Fritz_anav_interp(lum = 1e+44, ct = 40, rm = 60, ta = 1, al = 4, be = -0.5,
Fritz_anav = NULL)

SKIRTOR_anav_interp(lum = 1e+44, ct = 40, rm = 60, ta = 1, p = 1, q = 1,
SKIRTOR_anav = NULL)
}
\arguments{
\item{lum}{
Expand Down Expand Up @@ -49,6 +61,14 @@ The \option{Fritz} data. Providing this directly reduces disk IO since it will u
}
\item{SKIRTOR}{
The \option{SKIRTOR} data. Providing this directly reduces disk IO since it will use the copy already loaded into RAM. If not provided it will load the data from disk.
}
\item{Fritz_anav}{
The angle-averaged \code{Fritz_anav} template library. If NULL, it is loaded
with \code{data("Fritz_anav")}. Pass a preloaded library to avoid repeated disk IO.
}
\item{SKIRTOR_anav}{
The angle-averaged \code{SKIRTOR_anav} template library. If NULL, it is loaded
with \code{data("SKIRTOR_anav")}. Pass a preloaded library to avoid repeated disk IO.
}
}
\details{
Expand All @@ -70,7 +90,9 @@ Previously, we have found that an advantageous property of such two-phase medium
If \option{an} this is larger then \option{ct}/2 then by definition a significant component of the AGN accretion disk light is being attenuated by the torus (AKA type II AGN). If \option{an} is less then \option{ct}/2 then we have a direct line-of-sight to the AGN accretion disk and will observe much more UV flux in particular (AKA type I AGN, including blazars and quasars).
}
\value{
Numeric Matrix; first column is observed wavelength (Angstroms) and second column is observed luminosity (erg/s/Ang).
Data frame with columns \code{wave} (rest-frame wavelength in Angstroms) and
\code{lum} (luminosity density in erg/s/Ang). The angle-averaged helpers return
angle-averaged luminosity density rather than a particular viewing direction.
}
\references{
Feltre et al, 2012, MNRAS, 426, 120 \cr
Expand Down
22 changes: 20 additions & 2 deletions man/ProSpectSED.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ ProSpectSED(SFH = SFHfunc, z = 0.1, tau_birth = 1, tau_screen = 0.3, tau_AGN = 1
ff_frac_SF = 0.1, ff_power_SF = -0.1, sy_power_SF = -0.8, Te_AGN = 10000,
ff_frac_AGN = 0.1, ff_power_AGN = -0.1, sy_power_AGN = -0.8, AGNct = 40, AGNrm = 60,
AGNan = 30, AGNta = 1, AGNal = 4, AGNbe = -0.5, AGNp = 1, AGNq = 1, Eb = 0, L0 = 2175.8,
LFWHM = 470, IGMabsorb = 0, Inoue14_LAFcoef = NULL, Inoue14_DLAcoef = NULL, ...)
LFWHM = 470, IGMabsorb = 0, Inoue14_LAFcoef = NULL, Inoue14_DLAcoef = NULL,
AGN_screen_model = "viewing_angle", AGN_anav = NULL, ...)

ProSpectSEDlike(parm = c(8,9,10,10,0,-0.5,0.2), Data)
}
Expand Down Expand Up @@ -72,6 +73,12 @@ Object or scalar logical; optional. Pass in the Dale dust library \code{\link[Pr
}
\item{AGN}{
Object; optional. Pass in the AGN template to use. Must be one of \code{\link{AGN_UnOb}}, \code{\link{AGN_UnOb_Sparse}}, \code{\link[ProSpectData:Fritz]{Fritz}}, or \code{\link[ProSpectData:SKIRTOR]{SKIRTOR}}. These objects have classes attached, when ensures the correct AGN code is executed (so users should not simply try to load their own specific AGN model).
}
\item{AGN_screen_model}{
Character scalar; \code{"viewing_angle"} (default), \code{"angle_averaged"}, or \code{"None"}. Choice of AGN SED to calculate FIR emission due to UV attenuation by the ISM. The angle-averaged mode internally uses the matching \code{Fritz_anav} or \code{SKIRTOR_anav} template. \code{None} is equivalent to zero screen optical depth for the AGN only.
}
\item{AGN_anav}{
Object; optional. Pass in the angle-averaged AGN template to use when \option{AGN_screen_model} = \code{"angle_averaged"}. Must be one of \code{Fritz_anav} or \code{SKIRTOR_anav}. Providing this avoids reloading the averaged template from disk on each call.
}

\item{filtout}{
Expand Down Expand Up @@ -222,7 +229,18 @@ List, optional but recommended; pass in the spectral library directly. Must be o
List, optional but recommended; pass in the Dale dust library directly (should be one of \option{Dale_NormTot}, \option{Dale_NormSFR} otherwise will run, but not work correctly). If set to FALSE then there will be no FIR re-emission.
}
\item{Data$AGN}{
Data.frame, optional; pass in the AGN template to use. Must be one of \code{\link{AGN_UnOb}} or \code{\link{AGN_UnOb_Sparse}}.
Object, optional; pass in the viewing-angle AGN template to use. Accepts the
same template classes as \option{AGN}, including Fritz and SKIRTOR.
}
\item{Data$AGN_screen_model}{
Character scalar, optional; AGN emission mode passed to \code{ProSpectSED}.
It can also be supplied as \code{Data$arglist$AGN_screen_model}; a non-NULL
\code{Data$AGN_screen_model} takes precedence. Defaults to \code{"viewing_angle"}.
}
\item{Data$AGN_anav}{
Object, optional; matching angle-averaged AGN library passed to
\code{ProSpectSED}. It can also be supplied as \code{Data$arglist$AGN_anav};
a non-NULL \code{Data$AGN_anav} takes precedence. See \option{AGN_anav}.
}
\item{Data$filtout}{
List; required. Pass in the photometric filters directly. If \code{filters} is a vector of filter names, this can be achieved efficiently with a command like: filtout=foreach(i = filters)\%do\%{getfilt(i)} or filtout=foreach(i = filters)\%do\%{approxfun(getfilt(i))}, where the latter will be faster (see \code{\link{getfilt}}).
Expand Down
Loading