R/netGas_calculation.R

Defines functions netGasGC netGas

Documented in netGas netGasGC

#' Calculate the net product gas
#'
#' Two functions that allow to calculate the net amount of biogas produced by fermentations in a `BGF`.
#' Both allow to subtract the amount of gas produced by blanks from fermentations, but differ in the way the netGas is calculated and also in the experimental data they need as input.
#'
#' The function `netGas` uses the 'product' column of the `BioGasData` layer of a `BGF` to calculate the 'net_product' and can be used if no gas quality measurements are available.
#' When called, it uses the same assumed purity of the product gas for blanks and fermentations.
#' The expected use case is the analysis of AMPTS II generated data, where a methane concentration of 100 vol.% can be assumed due to CO2 absorption units of that system.
#'
#' @param x a `BGF`
#' @param purity either a `numeric` indicating the assumed purity (0 - 1) of the product gas for `netGas`, or a `character` or an `integer` referencing the column providing gas quality measurements in the `BioGasData` layer of a `BGF`.
#' @param substract_blank `logic`; default is `TRUE`. Should the mean product volume produced by blanks be subtracted from fermentations? Fermentations classified as Blanks must exist in the `BGF` (`BGF$metaData$Blank==TRUE`).
#' @param pos an `integer` indicating where the mass amounts of blanks in each fermentation are stored (see *Note*)
#' @param feedback `logic`, default is `FALSE`; If `TRUE`, the function will print a feedback to the console
#'
#' @note
#' To be able of subtracting the amount of gas produced by blank fermentations from the other fermentations, it is essential to provide the information of how much blank was used to inoculate each fermentation.
#' If this information is not known, it can be deduced from the inoculum to substrate ratio and the working load (mass or volume) of the fermentation.
#'
#' @returns a `BGF`
#'
#' @examples
#' # create an example BGF
#' myBGF <- BGF(
#'         ReactorLayout = c("2*Blank","Cellulose","2*S1 ctrl","2*S1 7d","2*S1 4d",
#'                           "2*S2 ctrl","2*S2 4d","2*S2 6d"),
#'         BlankLabel = "Blank",
#'         name = "myBGF",
#'         ProcessTemp = 42,
#'         MeasurementType = "AMPTSV2")
#'
#' # add data generated by an AMPTS II
#' myBGF <- add_bmp_measurement(
#'         x = myBGF,
#'         path = base::system.file("extdata","AMPTSV2.csv",package ="bgfanalyzer"))
#'
#' # convert data columns
#' myBGF <- cols_to_numeric(myBGF)
#'
#' # close gaps in data
#' myBGF <- close_gaps(myBGF)
#'
#' # calculate netGas
#' myBGF <- netGas(myBGF)
#'
#' @export
#'

# netGas() ####
netGas=function(x,purity=1,substract_blank=TRUE,pos=7,feedback=FALSE){
  if(isFALSE(class(x)=="BGF")){ # check if 'x' is class basic_BGF
    stop("'x' must be class 'BGF'!",
         call. = FALSE)
  }

  if(isTRUE(substract_blank)){
    blanks<-get_blanks(x) # Get names of blanks
    excl<-get_Excluded(x) # Get names of excluded reactors

    df<-subset(x[["BioGasData"]],x[["BioGasData"]][,"reactor"]%in%blanks) # subset to have only BioGasData of blanks
    df<-subset(df,!df[,"reactor"]%in%excl) # exclude a blank if needed

    vBlank=dplyr::pull(dplyr::reframe(product=mean(as.numeric(.data$product),rm.na=TRUE),.by = .data$time,.data = df),.data$product) # calculate the mean gas volume produced by the blanks
    names(vBlank)=as.character(dplyr::pull(dplyr::reframe(time=mean(as.numeric(.data$time)),.by = .data$time,.data = df),.data$time)) # name each volume by its respective time

    meta<-x[["metaData"]] # extract 'metaData'

    mBlbank<-subset(meta,meta$Blank==TRUE) # subset 'metaData' to have only obs  of the blank reactors
    mBlbank<-mean(as.numeric(dplyr::pull(subset(mBlbank,mBlbank$Excluded==FALSE),pos))) # get the mass of organics stored at 'pos' in 'metaData'


    mBlank_Sample<-as.numeric(dplyr::pull(meta,pos)) # get the masses of all reactors as stored at 'pos' in 'metaData'
    names(mBlank_Sample)<-rownames(meta) # name the masses by the respective reactors


    for(i in c(1:length(x[["BioGasData"]]$net_product))){ # subtract from each value in 'BioGasData$product' the amount of gas produced by the 'blank' proportion in that reactor

      x[["BioGasData"]]$net_product[i]<-c((as.numeric(x[["BioGasData"]]$product[i])-as.numeric(vBlank[as.character(x[["BioGasData"]]$time[i])])*(mBlank_Sample[x[["BioGasData"]]$reactor[i]]/mBlbank))*purity)

    }

    # give feedback
    if(isTRUE(feedback)){
      m1 <- paste0("Blank gas volume substracted from sample gas volume (",x$ExpParam$name,")...")
      
      message(m1)
      }
  }else{
    for(i in c(1:length(x[["BioGasData"]]$net_product))){ # copy each value in 'BioGasData$product' to 'BioGasData$netGas' and adjust gas purity if needed

      x[["BioGasData"]]$net_product[i]<-c(as.numeric(x[["BioGasData"]]$product[i])*purity)

    }

    # give feedback
    if(isTRUE(feedback)){
      m1 <- paste0("No blank gas volume substracted from sample gas volume (",x$ExpParam$name,")...")
                               
      message(m1)
      }

  }

  return(x) # return modified x
}

#' @rdname netGas
#'
#' @details
#' The function `netGasGC` uses the 'production' column instead of the 'product' column to calculate the 'net_product' column of the `BioGasData` layer of a `BGF`.
#' It furthermore needs a column providing gas quality measurements added to the `BioGasData` layer.
#'
#' @param percent `logic`; default is `TRUE`. Are the values in the column referenced by the 'purity' argument in percent or in an interval from 0 to 1?
#' @param na_replace a `numeric`. The default assumed concentration of target gas at the beginning of the fermentation.
#'
#' @examples
#' # create a second example BGF
#' myBGF2 <- from_standard_record(
#'         ReactorLayout = "A",
#'         ProcessTemp = 80,
#'         InocToSubRatio = .1,
#'         path = base::system.file("extdata","Fermentation_A.tsv",package ="bgfanalyzer"),
#'         time_col = 1,
#'         product_col = 3)
#'
#' # import gas quality data
#' gasq <- import_standard_record(
#'       ipath = base::system.file(
#'               "extdata",
#'               "gasq_A.tsv",
#'               package ="bgfanalyzer"),
#'       mkFRTime = "2025-01-15 17:00:00",
#'       FRTime_col = 1,
#'       units = "hours")
#'
#' # add gas quality data to
#' myBGF2 <- add_BG_parameter(myBGF2,gasq,"R1",3,2,name = "H2",cut_zero = TRUE)
#'
#' # ensure data integrity
#' myBGF2 <- update_BGF(myBGF2)
#'
#' # correct NA's
#' myBGF2 <- na_correction(myBGF2)
#'
#' # calculate production
#' myBGF2 <- calculate_flow_from_volume(myBGF2)
#'
#' # calculate net gas based on production
#' myBGF2 <- netGasGC(myBGF2,substract_blank = FALSE,purity = "H2")
#'
#' @export
#'

# netGasGC() ####
netGasGC=function(x,purity,percent=TRUE,substract_blank=TRUE,pos=7,na_replace=0,feedback=FALSE){
  if(isFALSE(class(x)=="BGF")){ # check if 'x' is class basic_BGF
    stop("'x' must be class 'BGF'!",
         call. = FALSE)
  }
  for(q in levels(x$BioGasData$reactor)){

  if(is.character(purity)) purity=grep(purity,names(x$BioGasData))

  x$BioGasData$net_product[which(x$BioGasData$reactor==q)[1]]=na_replace*x$BioGasData[which(x$BioGasData$reactor==q)[1],purity]

  if(isTRUE(percent)){
    for(i in which(x$BioGasData$reactor==q)[-1]) x$BioGasData$net_product[i]=x$BioGasData$production[i]*(x$BioGasData[i,purity]/100)
  }else{
    for(i in which(x$BioGasData$reactor==q)[-1]) x$BioGasData$net_product[i]=x$BioGasData$production[i]*x$BioGasData[i,purity]
  }


  for(i in which(x$BioGasData$reactor==q)[-1]) x$BioGasData$net_product[i]=x$BioGasData$net_product[i]+x$BioGasData$net_product[i-1]
    }

  if(isTRUE(substract_blank)){

    blanks<-get_blanks(x) # Get names of blanks
    excl<-get_Excluded(x) # Get names of excluded reactors

    df<-subset(x[["BioGasData"]],x[["BioGasData"]][,"reactor"]%in%blanks) # subset to have only BioGasData of blanks
    df<-subset(df,!df[,"reactor"]%in%excl) # exclude a blank if needed

    vBlank=dplyr::pull(dplyr::reframe(net_product=mean(as.numeric(.data$net_product),rm.na=TRUE),.by = .data$time,.data = df),.data$net_product) # calculate the mean gas volume produced by the blanks
    names(vBlank)=as.character(dplyr::pull(dplyr::reframe(time=mean(as.numeric(.data$time)),.by = .data$time,.data = df),.data$time)) # name each volume by its respective time

    meta<-x[["metaData"]] # extract 'metaData'

    mBlbank<-subset(meta,meta$Blank==TRUE) # subset 'metaData' to have only obs  of the blank reactors
    mBlbank<-mean(as.numeric(dplyr::pull(subset(mBlbank,mBlbank$Excluded==FALSE),pos))) # get the mass of organics stored at 'pos' in 'metaData'


    mBlank_Sample<-as.numeric(dplyr::pull(meta,pos)) # get the masses of all reactors as stored at 'pos' in 'metaData'
    names(mBlank_Sample)<-rownames(meta) # name the masses by the respective reactors


    for(i in c(1:length(x[["BioGasData"]]$net_product))){ # subtract from each value in 'BioGasData$produce' the amount of gas produced by the 'blank' proportion in that reactor

      x[["BioGasData"]]$net_product[i]<-c((as.numeric(x[["BioGasData"]]$net_product[i])-as.numeric(vBlank[as.character(x[["BioGasData"]]$time[i])])*(mBlank_Sample[x[["BioGasData"]]$reactor[i]]/mBlbank)))

    }

    # give feedback
    if(isTRUE(feedback)){
      m1 <- paste0("Blank gas volume substracted from sample gas volume (",x$ExpParam$name,")...")
      
      message(m1)
      }


  }

  return(x) # return modified x
}

Try the bgfanalyzer package in your browser

Any scripts or data that you put into this service are public.

bgfanalyzer documentation built on Sept. 26, 2026, 5:07 p.m.