From 98b5c9c575ab891670f07525fe83a1596c2eb937 Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 09:52:06 +0800 Subject: [PATCH 01/11] Update AGN.R --- R/AGN.R | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/R/AGN.R b/R/AGN.R index acc73f1..d81f2d6 100644 --- a/R/AGN.R +++ b/R/AGN.R @@ -66,3 +66,73 @@ 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()) + } + + 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()) + } + + 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)) + +} From a48c2aedb51539b5d723f91d6224ac71acae409b Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 09:53:44 +0800 Subject: [PATCH 02/11] Update ProSpect.R Adds in ability to use angle averaged AGN SED for ISM attenuation of AGN --- R/ProSpect.R | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/R/ProSpect.R b/R/ProSpect.R index f55c19d..247d46e 100644 --- a/R/ProSpect.R +++ b/R/ProSpect.R @@ -50,9 +50,17 @@ ProSpectSED = function(SFH = SFHfunc, IGMabsorb = 0, Inoue14_LAFcoef = NULL, Inoue14_DLAcoef = NULL, + AGN_emission = 'viewing_angle', + AGN_anav = NULL, ...) { #call = match.call() + if (!is.character(AGN_emission) || length(AGN_emission) != 1L || + is.na(AGN_emission) || + !AGN_emission %in% c('viewing_angle', 'angle_averaged')) { + stop("AGN_emission must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) + } + if(!is.null(waveout)){ waveout_max = max(waveout) }else{ @@ -173,10 +181,39 @@ ProSpectSED = function(SFH = SFHfunc, stop('Dale cannot be FALSE when using an AGN model!') } + if (AGN_emission == 'angle_averaged') { + if (!inherits(AGN, 'Fritz') && !inherits(AGN, 'SKIRTOR')) { + stop('Angle-averaged AGN emission requires a Fritz or SKIRTOR model') + } + if (inherits(AGN, 'Fritz')) { + if (is.null(AGN_anav)) { + data('Fritz_anav', envir = environment()) + AGN_anav = get('Fritz_anav', envir = environment()) + } + if (!inherits(AGN_anav, 'Fritz_anav')) { + stop("AGN_anav must be a Fritz_anav object when AGN is Fritz and AGN_emission = 'angle_averaged'") + } + } else { + if (is.null(AGN_anav)) { + data('SKIRTOR_anav', envir = environment()) + AGN_anav = get('SKIRTOR_anav', envir = environment()) + } + if (!inherits(AGN_anav, 'SKIRTOR_anav')) { + stop("AGN_anav must be a SKIRTOR_anav object when AGN is SKIRTOR and AGN_emission = 'angle_averaged'") + } + } + } + if(inherits(AGN, 'Fritz') | inherits(AGN, 'SKIRTOR')) { #Use new model if (inherits(AGN, 'Fritz')) { + if (AGN_emission == '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, @@ -188,6 +225,12 @@ ProSpectSED = function(SFH = SFHfunc, Fritz = AGN ) } else if (inherits(AGN, 'SKIRTOR')) { + if (AGN_emission == '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, @@ -203,6 +246,14 @@ 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_emission == '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, @@ -216,6 +267,14 @@ ProSpectSED = function(SFH = SFHfunc, L0 = L0, LFWHM = LFWHM ) + if (AGN_emission == '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 @@ -500,6 +559,20 @@ ProSpectSED = function(SFH = SFHfunc, } ProSpectSEDlike = function(parm = c(8, 9, 10, 10, 0, -0.5, 0.2), Data) { + if (!is.null(Data$AGN_emission)) { + Data$arglist$AGN_emission = Data$AGN_emission + } + if (!is.null(Data$AGN_anav)) { + Data$arglist$AGN_anav = Data$AGN_anav + } + if (!is.null(Data$arglist$AGN_emission) && + (!is.character(Data$arglist$AGN_emission) || + length(Data$arglist$AGN_emission) != 1L || + is.na(Data$arglist$AGN_emission) || + !Data$arglist$AGN_emission %in% c('viewing_angle', 'angle_averaged'))) { + stop("Data$AGN_emission must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) + } + if (is.null(Data$fit)) { Data$fit = 'optim' } From 6369eb4d03695baf279cf7df260a8505f38446aa Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 09:55:07 +0800 Subject: [PATCH 03/11] Update AGNinterp.Rd Adds in ability to use angle-averaged AGN SED for ISM attenuation --- man/AGNinterp.Rd | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/man/AGNinterp.Rd b/man/AGNinterp.Rd index 54191fc..8a3a2de 100644 --- a/man/AGNinterp.Rd +++ b/man/AGNinterp.Rd @@ -2,12 +2,18 @@ \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, @@ -15,6 +21,12 @@ Fritz_interp(lum = 1e+44, ct = 40, rm = 60, an = 30, ta = 1, al = 4, be = -0.5, 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}{ @@ -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{ @@ -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 From c88e229ce24d39b85babb4e1582c24f8c69ba76f Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 09:56:09 +0800 Subject: [PATCH 04/11] Update ProSpectSED.Rd Adds in the ability to use angle-averaged AGN SED for ISM attenuation --- man/ProSpectSED.Rd | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/man/ProSpectSED.Rd b/man/ProSpectSED.Rd index b25e4e9..3c9ee05 100644 --- a/man/ProSpectSED.Rd +++ b/man/ProSpectSED.Rd @@ -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_emission = "viewing_angle", AGN_anav = NULL, ...) ProSpectSEDlike(parm = c(8,9,10,10,0,-0.5,0.2), Data) } @@ -72,6 +73,27 @@ 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_emission}{ +Character scalar; \code{"viewing_angle"} (default) or \code{"angle_averaged"}. +The default reproduces the upstream behaviour: the AGN spectrum at \option{AGNan} +sets both the emergent AGN light and the energy absorbed and re-emitted by the +host dust screen. For Fritz or SKIRTOR models, \code{"angle_averaged"} instead +uses the angle-averaged AGN spectrum to compute screen heating and dust +re-emission, while the directly transmitted, emergent AGN spectrum is still +computed at \option{AGNan}. It does not replace the emergent AGN with an +angle-averaged spectrum. The screen is controlled by \option{tau_screen}, +\option{pow_screen}, and \option{alpha_SF_screen}. Angle-averaged mode requires +a Fritz or SKIRTOR model when the AGN is active. +} + \item{AGN_anav}{ +Object; optional preloaded angle-averaged AGN template library, used only when +\option{AGN_emission} is \code{"angle_averaged"}. Must have class +\code{Fritz_anav} for a Fritz \option{AGN}, or \code{SKIRTOR_anav} for a SKIRTOR +\option{AGN}. If NULL, the matching \code{Fritz_anav} or \code{SKIRTOR_anav} +dataset is loaded with \code{data()}; it must be available in an installed data +package. Passing a preloaded library avoids repeated disk IO. The ordinary +viewing-angle template is still supplied separately through \option{AGN}. } \item{filtout}{ @@ -222,7 +244,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_emission}{ +Character scalar, optional; AGN emission mode passed to \code{ProSpectSED}. +It can also be supplied as \code{Data$arglist$AGN_emission}; a non-NULL +\code{Data$AGN_emission} 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}}). From 1e59cc091775b04b05af30501e9717f5f8563db5 Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 09:58:39 +0800 Subject: [PATCH 05/11] Update ProSpectSED.Rd --- man/ProSpectSED.Rd | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/man/ProSpectSED.Rd b/man/ProSpectSED.Rd index 3c9ee05..5d12840 100644 --- a/man/ProSpectSED.Rd +++ b/man/ProSpectSED.Rd @@ -75,25 +75,10 @@ Object or scalar logical; optional. Pass in the Dale dust library \code{\link[Pr 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_emission}{ -Character scalar; \code{"viewing_angle"} (default) or \code{"angle_averaged"}. -The default reproduces the upstream behaviour: the AGN spectrum at \option{AGNan} -sets both the emergent AGN light and the energy absorbed and re-emitted by the -host dust screen. For Fritz or SKIRTOR models, \code{"angle_averaged"} instead -uses the angle-averaged AGN spectrum to compute screen heating and dust -re-emission, while the directly transmitted, emergent AGN spectrum is still -computed at \option{AGNan}. It does not replace the emergent AGN with an -angle-averaged spectrum. The screen is controlled by \option{tau_screen}, -\option{pow_screen}, and \option{alpha_SF_screen}. Angle-averaged mode requires -a Fritz or SKIRTOR model when the AGN is active. -} +Character vector; Choice of use of viewing_angle or angle_averaged 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. + } \item{AGN_anav}{ -Object; optional preloaded angle-averaged AGN template library, used only when -\option{AGN_emission} is \code{"angle_averaged"}. Must have class -\code{Fritz_anav} for a Fritz \option{AGN}, or \code{SKIRTOR_anav} for a SKIRTOR -\option{AGN}. If NULL, the matching \code{Fritz_anav} or \code{SKIRTOR_anav} -dataset is loaded with \code{data()}; it must be available in an installed data -package. Passing a preloaded library avoids repeated disk IO. The ordinary -viewing-angle template is still supplied separately through \option{AGN}. +Object; optional. Pass in the angle-averaged AGN template to use when \option{AGN_emission} = \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}{ From 51c5f609f9931a3dfb2958b4df27bbf5021caf3c Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 10:11:40 +0800 Subject: [PATCH 06/11] Update ProSpect.R Renamed AGN_emission to AGN_screen_model for clarity --- R/ProSpect.R | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/R/ProSpect.R b/R/ProSpect.R index 247d46e..8d41531 100644 --- a/R/ProSpect.R +++ b/R/ProSpect.R @@ -50,15 +50,15 @@ ProSpectSED = function(SFH = SFHfunc, IGMabsorb = 0, Inoue14_LAFcoef = NULL, Inoue14_DLAcoef = NULL, - AGN_emission = 'viewing_angle', + AGN_screen_model = 'viewing_angle', AGN_anav = NULL, ...) { #call = match.call() - if (!is.character(AGN_emission) || length(AGN_emission) != 1L || - is.na(AGN_emission) || - !AGN_emission %in% c('viewing_angle', 'angle_averaged')) { - stop("AGN_emission must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) + 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')) { + stop("AGN_screen_model must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) } if(!is.null(waveout)){ @@ -181,7 +181,7 @@ ProSpectSED = function(SFH = SFHfunc, stop('Dale cannot be FALSE when using an AGN model!') } - if (AGN_emission == 'angle_averaged') { + if (AGN_screen_model == 'angle_averaged') { if (!inherits(AGN, 'Fritz') && !inherits(AGN, 'SKIRTOR')) { stop('Angle-averaged AGN emission requires a Fritz or SKIRTOR model') } @@ -191,7 +191,7 @@ ProSpectSED = function(SFH = SFHfunc, AGN_anav = get('Fritz_anav', envir = environment()) } if (!inherits(AGN_anav, 'Fritz_anav')) { - stop("AGN_anav must be a Fritz_anav object when AGN is Fritz and AGN_emission = 'angle_averaged'") + stop("AGN_anav must be a Fritz_anav object when AGN is Fritz and AGN_screen_model = 'angle_averaged'") } } else { if (is.null(AGN_anav)) { @@ -199,7 +199,7 @@ ProSpectSED = function(SFH = SFHfunc, AGN_anav = get('SKIRTOR_anav', envir = environment()) } if (!inherits(AGN_anav, 'SKIRTOR_anav')) { - stop("AGN_anav must be a SKIRTOR_anav object when AGN is SKIRTOR and AGN_emission = 'angle_averaged'") + stop("AGN_anav must be a SKIRTOR_anav object when AGN is SKIRTOR and AGN_screen_model = 'angle_averaged'") } } } @@ -208,7 +208,7 @@ ProSpectSED = function(SFH = SFHfunc, inherits(AGN, 'SKIRTOR')) { #Use new model if (inherits(AGN, 'Fritz')) { - if (AGN_emission == 'angle_averaged') { + 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 @@ -225,7 +225,7 @@ ProSpectSED = function(SFH = SFHfunc, Fritz = AGN ) } else if (inherits(AGN, 'SKIRTOR')) { - if (AGN_emission == 'angle_averaged') { + 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 @@ -246,7 +246,7 @@ 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_emission == 'angle_averaged') { + 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 @@ -267,7 +267,7 @@ ProSpectSED = function(SFH = SFHfunc, L0 = L0, LFWHM = LFWHM ) - if (AGN_emission == 'angle_averaged') { + 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, @@ -559,18 +559,18 @@ ProSpectSED = function(SFH = SFHfunc, } ProSpectSEDlike = function(parm = c(8, 9, 10, 10, 0, -0.5, 0.2), Data) { - if (!is.null(Data$AGN_emission)) { - Data$arglist$AGN_emission = Data$AGN_emission + 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_emission) && - (!is.character(Data$arglist$AGN_emission) || - length(Data$arglist$AGN_emission) != 1L || - is.na(Data$arglist$AGN_emission) || - !Data$arglist$AGN_emission %in% c('viewing_angle', 'angle_averaged'))) { - stop("Data$AGN_emission must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) + 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'))) { + stop("Data$AGN_screen_model must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) } if (is.null(Data$fit)) { From 6aadd99dbcc812091cb5d48fcb234d31d81c2e5f Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 10:12:36 +0800 Subject: [PATCH 07/11] Update ProSpectSED.Rd Renamed AGN_emission to AGN_screen_model for clarity --- man/ProSpectSED.Rd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/man/ProSpectSED.Rd b/man/ProSpectSED.Rd index 5d12840..04f0936 100644 --- a/man/ProSpectSED.Rd +++ b/man/ProSpectSED.Rd @@ -20,7 +20,7 @@ ProSpectSED(SFH = SFHfunc, z = 0.1, tau_birth = 1, tau_screen = 0.3, tau_AGN = 1 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, - AGN_emission = "viewing_angle", AGN_anav = NULL, ...) + AGN_screen_model = "viewing_angle", AGN_anav = NULL, ...) ProSpectSEDlike(parm = c(8,9,10,10,0,-0.5,0.2), Data) } @@ -74,11 +74,11 @@ 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_emission}{ + \item{AGN_screen_model}{ Character vector; Choice of use of viewing_angle or angle_averaged 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. } \item{AGN_anav}{ -Object; optional. Pass in the angle-averaged AGN template to use when \option{AGN_emission} = \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. +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}{ @@ -232,10 +232,10 @@ List, optional but recommended; pass in the Dale dust library directly (should b 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_emission}{ + \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_emission}; a non-NULL -\code{Data$AGN_emission} takes precedence. Defaults to \code{"viewing_angle"}. +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 From 5f37816ace9fe86f119dcf65585a88d0aaa34f72 Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 11:44:54 +0800 Subject: [PATCH 08/11] Update plots.R Fixed plotting function to use correct starUnAtten ylim upper limit --- R/plots.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/plots.R b/R/plots.R index 11b51ce..2477b7a 100644 --- a/R/plots.R +++ b/R/plots.R @@ -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)) From d4565089e7535720d410057aaec83896633e6dc4 Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 12:20:48 +0800 Subject: [PATCH 09/11] Update ProSpect.R Added 'None' option to remove AGN ISM attenuation --- R/ProSpect.R | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/R/ProSpect.R b/R/ProSpect.R index 8d41531..2169e2c 100644 --- a/R/ProSpect.R +++ b/R/ProSpect.R @@ -57,8 +57,8 @@ ProSpectSED = function(SFH = SFHfunc, 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')) { - stop("AGN_screen_model must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) + !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)){ @@ -181,27 +181,9 @@ ProSpectSED = function(SFH = SFHfunc, stop('Dale cannot be FALSE when using an AGN model!') } - if (AGN_screen_model == 'angle_averaged') { - if (!inherits(AGN, 'Fritz') && !inherits(AGN, 'SKIRTOR')) { - stop('Angle-averaged AGN emission requires a Fritz or SKIRTOR model') - } - if (inherits(AGN, 'Fritz')) { - if (is.null(AGN_anav)) { - data('Fritz_anav', envir = environment()) - AGN_anav = get('Fritz_anav', envir = environment()) - } - if (!inherits(AGN_anav, 'Fritz_anav')) { - stop("AGN_anav must be a Fritz_anav object when AGN is Fritz and AGN_screen_model = 'angle_averaged'") - } - } else { - if (is.null(AGN_anav)) { - data('SKIRTOR_anav', envir = environment()) - AGN_anav = get('SKIRTOR_anav', envir = environment()) - } - if (!inherits(AGN_anav, 'SKIRTOR_anav')) { - stop("AGN_anav must be a SKIRTOR_anav object when AGN is SKIRTOR and AGN_screen_model = 'angle_averaged'") - } - } + 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') | @@ -257,7 +239,7 @@ ProSpectSED = function(SFH = SFHfunc, 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, @@ -332,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, @@ -569,8 +551,8 @@ ProSpectSEDlike = function(parm = c(8, 9, 10, 10, 0, -0.5, 0.2), Data) { (!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'))) { - stop("Data$AGN_screen_model must be either 'viewing_angle' or 'angle_averaged'.", call. = FALSE) + !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)) { From 291f2404c8f89370c2b5c3cfe14640d22c83b80c Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 12:22:01 +0800 Subject: [PATCH 10/11] Update AGN.R Added error messages to pre-loading AGN data --- R/AGN.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/AGN.R b/R/AGN.R index d81f2d6..a0ea34f 100644 --- a/R/AGN.R +++ b/R/AGN.R @@ -74,6 +74,9 @@ Fritz_anav_interp = function(lum = 1e+44, ct = 40, rm = 60, ta = 1, al = 4, be = 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) @@ -108,6 +111,9 @@ SKIRTOR_anav_interp = function(lum = 1e+44, ct = 40, rm = 60, ta = 1, p = 1, q = 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) From b1c5c94540ac8e9bc180354d4d0a9356c1aae94c Mon Sep 17 00:00:00 2001 From: Adam Marshall <53895662+adamm2603@users.noreply.github.com> Date: Fri, 6 Nov 2026 12:25:52 +0800 Subject: [PATCH 11/11] Update ProSpectSED.Rd Added 'None' option to avoid AGN ISM attenuation. --- man/ProSpectSED.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/ProSpectSED.Rd b/man/ProSpectSED.Rd index 04f0936..0547fd7 100644 --- a/man/ProSpectSED.Rd +++ b/man/ProSpectSED.Rd @@ -75,7 +75,7 @@ Object or scalar logical; optional. Pass in the Dale dust library \code{\link[Pr 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 vector; Choice of use of viewing_angle or angle_averaged 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. +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.