4949# ' is the normal distribution function and sigma(BMD) is the SD at the
5050# ' benchmark dose.
5151# ' @param interval character string specifying the type of confidence interval
52- # ' to use: "boot" (default) or "none"
52+ # ' to use: "boot" (default), "delta" or "none"
5353# '
5454# ' "boot" - BMDL is based on percentile bootstrapping.
5555# '
56+ # ' "delta" - BMDL is based on the delta method.
57+ # '
5658# ' "none" - no confidence interval is computed.
5759# ' @param R number of bootstrap samples. Ignored if \code{interval = "none"}
5860# ' @param level numeric value specifying the levle of the confidence interval
113115# ' def = "hybridExc", R = 50, level = 0.95, progressInfo = TRUE, display = TRUE)
114116# '
115117# ' @export
116- bmdHetVar <- function (object , bmr , backgType = c(" absolute" , " hybridSD" , " hybridPercentile" ), backg = NA , def = c(" hybridExc" , " hybridAdd" ), interval = c(" boot" , " none" ), R = 1000 , level = 0.95 , bootType = " nonparametric" , progressInfo = TRUE , display = TRUE ){
118+ bmdHetVar <- function (object , bmr , backgType = c(" absolute" , " hybridSD" , " hybridPercentile" ), backg = NA , def = c(" hybridExc" , " hybridAdd" ), interval = c(" boot" , " delta " , " none" ), R = 1000 , level = 0.95 , bootType = " nonparametric" , progressInfo = TRUE , display = TRUE ){
117119 # ## Assertions ###
118120 # object
119121 if (! inherits(object ," drcHetVar" )){
@@ -158,14 +160,19 @@ bmdHetVar <- function(object, bmr, backgType = c("absolute", "hybridSD", "hybrid
158160
159161 level <- 1 - 2 * (1 - level )
160162
163+ # Model parameters
164+ curveParInd <- 1 : length(object $ curvePar )
165+ sigmaParInd <- (length(object $ curvePar )+ 1 ): (length(object $ curvePar )+ length(object $ sigmaPar ))
166+
161167 # SLOPE
162168 slope <- drop(ifelse(object $ curve(0 )- object $ curve(Inf )> 0 ," decreasing" ," increasing" ))
163169 if (is.na(object $ curve(0 )- object $ curve(Inf ))){
164170 slope <- drop(ifelse(object $ curve(0.00000001 )- object $ curve(100000000 )> 0 ," decreasing" ," increasing" ))
165171 }
166172
167- # sigmaFun
168- sigmaFun0 <- object $ sigmaFun # sigmaFun(object, var.formula)
173+ # functions
174+ curveFun0 <- object $ funList $ curveFun
175+ sigmaFun0 <- object $ funList $ sigmaFun # sigmaFun(object, var.formula)
169176
170177 # bmrScaled
171178 if (slope == " increasing" ){
@@ -174,50 +181,51 @@ bmdHetVar <- function(object, bmr, backgType = c("absolute", "hybridSD", "hybrid
174181 if (is.na(backg )){
175182 stop(' backgType = absolute, but backg not supplied' )
176183 }
177- p0 <- 1 - pnorm((backg - object $ curve( 0 )) / sigmaFun0(0 ))
184+ p0 <- function ( par ) 1 - pnorm((backg - curveFun0( 0 , par [ curveParInd ] )) / sigmaFun0(0 , sigmaPar = par [ sigmaParInd ], curvePar = par [ curveParInd ] ))
178185 }
179186 if (identical(backgType , " hybridPercentile" )) {
180- p0 <- ifelse(is.na(backg ),1 - 0.9 ,1 - backg )
187+ p0 <- function ( par ) ifelse(is.na(backg ),1 - 0.9 ,1 - backg )
181188 }
182189 if (identical(backgType ," hybridSD" )) {
183- p0 <- ifelse(is.na(backg ), 1 - pnorm(2 ), 1 - pnorm(backg ))
190+ p0 <- function ( par ) ifelse(is.na(backg ), 1 - pnorm(2 ), 1 - pnorm(backg ))
184191 }
185192
186193 # BMRSCALED
187194 bmrScaled <- switch (
188195 def ,
189- hybridExc = function (x ){ sigmaFun0(x ) *
190- (qnorm(1 - p0 ) - qnorm(1 - p0 - (1 - p0 )* bmr )) + object $ curve( 0 )},
191- hybridAdd = function (x ){ sigmaFun0(x ) *
192- (qnorm(1 - p0 ) - qnorm(1 - (p0 + bmr ))) + object $ curve( 0 )}
196+ hybridExc = function (x , par ){ sigmaFun0(x ) *
197+ (qnorm(1 - p0( par )) - qnorm(1 - p0( par ) - (1 - p0 )* bmr )) + curveFun0( 0 , par [ curveParInd ] )},
198+ hybridAdd = function (x , par ){ sigmaFun0(x ) *
199+ (qnorm(1 - p0( par )) - qnorm(1 - (p0( par ) + bmr ))) + curveFun0( 0 , par [ curveParInd ] )}
193200 )
194201 } else {
195202 # BACKGROUND
196203 if (identical(backgType ," absolute" )) {
197204 if (is.na(backg )){
198205 stop(' backgType = absolute, but backg not supplied' )
199206 }
200- p0 <- pnorm((backg - object $ curve( 0 )) / sigmaFun0(0 ))
207+ p0 <- function ( par ) pnorm((backg - curveFun0( 0 , par [ curveParInd ] )) / sigmaFun0(0 , sigmaPar = par [ sigmaParInd ], curvePar = par [ curveParInd ] ))
201208 }
202209 if (identical(backgType , " hybridPercentile" )) {
203- p0 <- ifelse(is.na(backg ),0.1 ,backg )
210+ p0 <- function ( par ) ifelse(is.na(backg ),0.1 ,backg )
204211 }
205212 if (identical(backgType ," hybridSD" )) {
206- p0 <- ifelse(is.na(backg ), pnorm(- 2 ), pnorm(- backg ))
213+ p0 <- function ( par ) ifelse(is.na(backg ), pnorm(- 2 ), pnorm(- backg ))
207214 }
208215
209216 # BMRSCALED
210217 bmrScaled <- switch (
211218 def ,
212- hybridExc = function (x ){ sigmaFun0(x ) *
213- (qnorm(p0 ) - qnorm(bmr + (1 - bmr ) * p0 )) + object $ curve( 0 )},
214- hybridAdd = function (x ){ sigmaFun0(x ) *
215- (qnorm(p0 ) - qnorm(bmr + p0 )) + object $ curve( 0 )}
219+ hybridExc = function (x , par ){ sigmaFun0(x , sigmaPar = par [ sigmaParInd ], curvePar = par [ curveParInd ] ) *
220+ (qnorm(p0( par )) - qnorm(bmr + (1 - bmr ) * p0( par ))) + curveFun0( 0 , par [ curveParInd ] )},
221+ hybridAdd = function (x , par ){ sigmaFun0(x , sigmaPar = par [ sigmaParInd ], curvePar = par [ curveParInd ] ) *
222+ (qnorm(p0( par )) - qnorm(bmr + p0( par ))) + curveFun0( 0 , par [ curveParInd ] )}
216223 )
217224 }
218225
219226 # BMD ESTIMATION
220- f0 <- function (x ) object $ curve(x ) - bmrScaled(x )
227+ par0 <- c(object $ curvePar , object $ sigmaPar )
228+ f0 <- function (x ) curveFun0(x , par0 [curveParInd ]) - bmrScaled(x , par0 )
221229 interval0 <- range(object $ dataList $ dose , na.rm = TRUE )
222230 uniroot0 <- try(uniroot(f = f0 , interval = interval0 ), silent = TRUE )
223231
@@ -228,17 +236,34 @@ bmdHetVar <- function(object, bmr, backgType = c("absolute", "hybridSD", "hybrid
228236 bmdEst <- uniroot0 $ root
229237 }
230238
239+
231240 # INTERVAL
232241 interval <- match.arg(interval )
233242 if (identical(interval , " none" )){
234243 BMDL <- NA
235244 BMDU <- NA
236- } else {
237- # drc_obj <- eval(substitute(drm(formula0, data = object$data, fct = fct0, type = "continuous", control = drmc(maxIt = 1, noMessage = TRUE)),
238- # list(formula0 = object$formula,
239- # fct0 = object$fct
240- # )))
241- # bootDataList <- bootDataGen(drc_obj, R=R, bootType="nonparametric",aggregated=FALSE)
245+ SDbmd <- NA
246+ } else if (identical(interval , " delta" )){
247+ if (! requireNamespace(" numDeriv" )){
248+ stop(' package "numDeriv" must be installed to compute delta confidence intervals with bmdHetVar' )
249+ }
250+
251+ getBmdEst <- function (par ){
252+ f0 <- function (x ) curveFun0(x , par [curveParInd ]) - bmrScaled(x , par )
253+ interval0 <- range(object $ dataList $ dose , na.rm = TRUE )
254+ uniroot0 <- try(uniroot(f = f0 , interval = interval0 ), silent = TRUE )
255+ bmdEst <- as.numeric(uniroot0 $ root )
256+ }
257+
258+ dBmd <- try(numDeriv :: grad(getBmdEst , par0 ))
259+
260+ Vbmd <- dBmd %*% vcov(object ) %*% dBmd
261+ SDbmd <- sqrt(Vbmd )
262+
263+ BMDL <- qnorm(c(1 - level )/ 2 , mean = bmdEst , sd = SDbmd )
264+ BMDU <- qnorm(1 - (1 - level )/ 2 , mean = bmdEst , sd = SDbmd )
265+
266+ } else if (identical(interval , " boot" )) {
242267 bootDataList <- bootDataGenHetVar(object , R = R , bootType = bootType )
243268
244269 bmdHetVarBoot <- function (bootData ){
@@ -265,9 +290,11 @@ bmdHetVar <- function(object, bmr, backgType = c("absolute", "hybridSD", "hybrid
265290 if (length(boot0 ) == 0 ){
266291 BMDL <- NA
267292 BMDU <- NA
293+ SDbmd <- NA
268294 } else {
269295 BMDL <- quantile(boot0 ,p = c(1 - level ), na.rm = TRUE ) # ABC percentile lims.
270296 BMDU <- quantile(boot0 ,p = c(level ), na.rm = TRUE )
297+ SDbmd <- sd(boot0 )
271298 }
272299 }
273300
@@ -282,6 +309,7 @@ bmdHetVar <- function(object, bmr, backgType = c("absolute", "hybridSD", "hybrid
282309
283310 resBMD <- list (Results = resMat ,
284311 bmrScaled = bmrScaled ,
312+ SE = SDbmd ,
285313 interval = bmdInterval ,
286314 model = object )
287315 class(resBMD ) <- c(" bmdHetVar" , " bmd" )
0 commit comments