Creating a `BGF` without Input Files

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

What this vignette is about

This vignette is the last of three workflow vignettes focusing on how to get data into a BGF. It introduces the "manual" MeasurementType, which requires no external data files for input.

BGF's of that measurement type can be useful during experiment conception but also allow to enter experimental parameters directly in R, e.g.when measurement values of accumulating exhaust gas (= BioGasData$product-values) are recorded employing syringes instead of digital gas counters.

This vignette covers the general methods of how to manually enter or alter values in a BGF and touches topic of experimental conception that have not yet been explained in the previous vignettes.

Setting up a manual BGF

A manual BGF can be created using BGF() and explicitly setting the MeasurementType argument. Let's build a BGF for two fermentations of Layout "A" and "B".

# load package
library(bgfanalyzer)

# create a BGF
myBGF <- BGF(ReactorLayout = c("A","B"),MeasurementType = "manuel")

# print it to the console
myBGF

The BGF was created but actually has carries no information. However, this will change soon, as we start to add our data.

First lets inspect the ExpParam-layer:

# print ExpParam-layer
print(myBGF$ExpParam)

As we can see, a default name was created and a default inoculum to substrate ration (InocToSubRatio) was specified. Furthermore, the MeasurementType is manual and was declared during object creation with BGF().

Modify ExpParam

Lets continue with specifying a value for ProcessTemp, renaming the BGF and adding a new parameter representing a time scale unit.

# set a value for ProcessTemp
myBGF$ExpParam$ProcessTemp=52 # 52°C is a good temperature for thermophilic anaerobic digestion

# alternatively use alter_whatever() to modify existing entries in ExpParam
myBGF <- alter_whatever(myBGF,layer = "ExpParam",what = "name",value = "manualBGF")

# new parameters can be added using add_ExpParam()
myBGF <- add_ExpParam(myBGF,what = c("timeScale"="Day"))

# inspect the changes
print(myBGF$ExpParam)

ExpParam has now 5 parameters and the values of ProcessTemp and name have changed.

Note that we used two different ways to modify existing values in ExpParam. While the process temperature was specified using simple S3 syntax, the renaming was done using a dedicated package function.

In addition, take care to provide new parameters as tag-value pairs, when adding them to a BGF with add_ExpParam(). The tag must be a character but the subsequent value can have any format.

Modify metaData

Next, we want to see how to enter and alter information within the metaData-layer of our BGF. Remember, unless like ExpParam, metaData is a data.frame with one row per fermentation.

# inspect the current metaData
myBGF$metaData

When inspecting the current metaData-layer we see one line per fermentation. None of our fermentations is classified as 'Blank', nor marked as excluded.

We can add new meta data, like the concentration of volatile solutes (VS) for each fermentation as follows:

# add VS concentration
myBGF <- add_metaData(myBGF,what = c(2.8,1.9),lab = "cVS")

# inspect changes
myBGF$metaData

For our experiment imagine a situation, where fermentation A is used to inoculate fermentation B. This would make A a suitable 'Blank' with regard to B. Furthermore, the fermentations should be carried out with a working volume of 5L.

We can set fermentation A to 'Blank' like this:

# change the status of Fermentation A to Blank=TRUE
myBGF <- alter_whatever(myBGF,layer = "metaData",
                        what = "Blank",value = TRUE,ID = "R1")

# inspect change
myBGF$metaData

Fermentation A is now marked as 'Blank'. We can use the function calc_inoc_matrix_from_metaData() to generate a inoculation matrix telling how inoculum (the 'Blank') and substrate should be mixed together based on the InocToSubRatio parameter of the BGF, and in that case the VS concentration of the fermentations A and B.

Note, that we could also calculate a COD- (chemical oxygen demand), or total solutes-based inoculation matrix, if the respective concentration is stored in metaData.

# calculate a VS-based inoculation matrix
InocMatrix <- calc_inoc_matrix_from_metaData(myBGF,col = 4,reactor = 5000) 
# reactor = 5000 for a 5L reactor
InocMatrix

For fermentation A (R1, the 'Blank'), the whole reactor is filled with inoculum, and for fermentation B (R2), r InocMatrix["Inoculum","R2"] ml inoculum (fermentation A, R1) are mixed with r InocMatrix["Substrate","R2"] ml fresh substrate.

For being able to subtract the amount of gas produced by the 'Blank' proportion in a fermentation, one must know the mass of organics (volatile solutes in gram for our example case) originating from the inoculum. As we have the inoculation matrix and the VS concentration for each fermentation, we can add the amount of VS in inoculum and substrate to metaData.

# add inoculum mass for each fermentation
myBGF <- add_metaData(myBGF,
                      what = as.numeric(InocMatrix["Inoculum",])*(myBGF$metaData["R1","cVS"]/100),
                      lab = "mInoc")

# add substrate mass for each fermentation
myBGF <- add_metaData(myBGF,
                      what = as.numeric(InocMatrix["Substrate",])*(myBGF$metaData["R2","cVS"]/100),
                      lab = "mSub")

Modify BioGasData

Our BGF has been created and a lab experiment was successfully designed. Now we are ready to add experimental data.

Imagine, in our hypothetical lab we have a fermentation system consisting of a tempered and stirred reactor, and an analog gas counter where we can manually read the accumulating exhaust gas volume.

We start the experiment and read the gas counter value once each day for 30 days. Doing this allows to add one new product value each day using add_BG_measurement()

Let's enter a value for the fermentation with layout A on the day the experiment starts (day 0).

# add a first value
myBGF <- add_BG_measurement(myBGF,
                            reactor = "R1",
                            time = 0,
                            col = "product",
                            measurement = 0)

# have a look at BioGasData upon value addition
myBGF$BioGasData

We added '0' as the product value at 'time= 0' as in the beginning of a fermentation, no biogas has been formed yet.

Now we continue to add one measurement each day for the following 30 days using the same command. We will generate some random gas measurements for our example assuming that the fermentation has a low but constant gas production:

# set seed
set.seed(656)

# generate a vector with 30 random numbers between 0.85 and 1.15
gas <- runif(30,0.85,1.15)

# convert these random numbers to hypothetical gas counter values
## assume 120 ml gas per value
gas <- gas * 120
## accumulate 'daily production'
for(i in c(2:length(gas))) gas[i]=c(gas[i]+gas[i-1])

# add hypothetical gas counter values to BGF
for(i in c(1:length(gas))) myBGF <- add_BG_measurement(myBGF,
                            reactor = "R1",
                            time = i,
                            col = "product",
                            measurement = gas[i])

# look at the end of BioGasData-layer to see the effect
tail(myBGF$BioGasData)

We successfully entered product values for the 'Blank' fermentation with layout A. Next, we will add further values for the fermentation with layout B.

Like before, we start with a '0' for the day the fermentation began.

# add a first value
myBGF <- add_BG_measurement(myBGF,
                            reactor = "R2",
                            time = 0,
                            col = "product",
                            measurement = 0)

# look at the end of BioGasData-layer to see the effect
tail(myBGF$BioGasData)

Let's assume for fermentation B to produce a lot of gas in the beginning, but less gas in the end:

# final product around
final_p = 25000

# set max slope
max_slope = 0.31

products <- final_p * (1 - exp(-max_slope * (0:(length(gas)))))
# convert the random numbers to hypothetical gas counter values
gas = products[c(2:31)]

for(i in c(1:length(gas))) myBGF <- add_BG_measurement(myBGF,
                            reactor = "R2",
                            time = i,
                            col = "product",
                            measurement = gas[i])

# look at the end of BioGasData-layer to see the effect
tail(myBGF$BioGasData)

Now that we entered product values for both fermentation, we can continue by calculating further standard fermentation parameters, like production or net gas. For net gas calculation we assume a methane (target gas) concentration of 60 vol.%.

# convert standard parameters to numeric
myBGF <- cols_to_numeric(myBGF,c(2:7))

# ensure internal logic of the BGF
myBGF <- update_BGF(myBGF)

# calculate production
myBGF <- calculate_flow_from_volume(myBGF)

# and relative production
myBGF <- relative_production(myBGF)

# calculate net gas (subtract Blank)
myBGF <- netGas(myBGF,purity = 0.6,pos = 5)

# calculate yield
myBGF <- calc_yield(myBGF,pos = 6)

# summarize yield
myBGF <- summarize_yield(myBGF)

# print the BGF to the console
myBGF

Finally, we build a manual BGF for two fermentations and entered product values entirely using R without the need of external files with input data! The manual BGF created that way allow the same visualizations techniques described in the other vignettes. They can be subset and merged like/ with other BGF's.

manual BGF's allow max flexibility

Compared to the other two workflows, the commercial and standard workflow, the manual BGF's offer a broader degree of freedom to the user. However, with this increased freedom comes also increased responsibility during data processing.

The same functions used during the manual workflow are also called behind the scenes during the other workflows.

BGF's created by either workflow are fully compatible to each other and thus can be merged, subset or re-arranged.

The manual workflow with it's high flexibility includes all building bricks needed to develop own advanced workflows, allowing to adapt the potential of bgfanalyzer all possible fermentation systems.



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.