library(tidyverse)
# building col names
<- c(
chamber_colnames "port", "valvestatus", "chamberstatus",
"aux1", "aux2", "aux3", "aux4", "aux5",
"temperaturev", "pressure"
)<- c(
log_colnames "epochtime",
rep(chamber_colnames, times = 12)
)
<- list.files(
chamber_log_read "ex_log",
full.names = TRUE
|>
) map_dfr(
read_log,col_names = log_colnames
)# read_log("ex_log/FRMonitor_0012.log", col_names = log_colnames)
# repeated colnames are normal
<- chamber_log_read |>
chamber_log_all pivot_longer(!c(epochtime), names_to = c(".value", "variable"), names_sep = "_") |>
filter(
%in% c(1:12) # we filter out all the rows with port -1
port |>
) arrange(epochtime) |> # just to be sure
mutate( # without grouping
chamber = case_when(
%in% c(1:3) ~ "open",
chamberstatus == 0 ~ "closed"
chamberstatus
),change_id = consecutive_id(port, chamberstatus), #detecting if same port but new measurement
datetime = as_datetime(epochtime) # we work in datetime
|>
) filter(
# chamberstatus %in% c(1:3) # very conservative, we can adjust the focus window later in flux_fitting
== 1
chamberstatus # valvestatus == 10
|>
) mutate(
measurement_id = consecutive_id(change_id) # just getting rid of the missing id after filter
)
<- chamber_log_all |>
chamber_log mutate(
.by = c(measurement_id),
closing = min(datetime) - 300, # can be recut in flux_fitting, but so we see better
opening = max(datetime) + 300
|>
) select(measurement_id, port, closing, opening) |>
distinct()
# We make a separate df for temp and pressure so we keep the 4 seconds reads
<- chamber_log_all |>
chamber_temp_pres mutate(
air_temp = temperaturev * 15, # need to ask the exact conversion factor, for now this one makes sense
pressure = pressure / 101.325 # need atm for fluxible
|>
) select(datetime, air_temp, pressure)
# View(chamber_log_all)
Full tutorial
Importing the data
In this section we will use the data in the ex_data folder. More ressources on data import are available in this vignette on the fluxible website.
Importing log file
Importing the log and turning it into a dataframe with chamber ID (port nb), chamber closing time and re-opening time.
Possible improvements
- take into account the chamber status better and use it to by-pass the start and end cuts in flux_fitting. Opening and closing status would be “cut” (not used for fitting but visible on the plot), and fully open would be “keep”.
- keep the other columns
- Because of the inconsistant offset between the closing of the chamber and the start of the flux, it is difficult to make a proper record of start/end of fluxes.
Importing data file
<- list.files(
data_read "ex_data",
full.names = TRUE
|>
) map_dfr(
read_table
)# read_table("ex_data/JFAADS2294-20241211-193921-DataLog_User.dat")
<- data_read |>
data mutate(
f_datetime = as_datetime(paste(DATE, TIME))
|>
) left_join(chamber_temp_pres, by = join_by(f_datetime == datetime)) |> # adding air temp and pressure here
select(f_datetime, CO2_dry, air_temp, pressure) # we keep it simple for now and work only on CO2
# View(data)
Processing the data
library(fluxible)
<- flux_match(
conc raw_conc = data,
field_record = chamber_log,
f_datetime = f_datetime,
start_col = closing,
end_col = opening,
fixed_length = FALSE,
time_diff = -15000 # 4h10
|>
) drop_na(CO2_dry)
# View(conc)
<- flux_fitting(
conc_fit conc_df = conc,
f_conc = CO2_dry,
fit_type = "linear",
# fit_type = "exp_zhao18",
start_cut = 300,
end_cut = 300
)#> Warning in flux_fitting(conc_df = conc, f_conc = CO2_dry, fit_type = "linear", :
#> fluxID 45 : slope was estimated on 216 points out of 857 seconds
#> fluxID 53 : slope was estimated on 851 points out of 861 seconds
#> fluxID 66 : slope was estimated on 852 points out of 853 seconds
#> fluxID 69 : slope was estimated on 172 points out of 853 seconds
#> fluxID 70 : slope was estimated on 849 points out of 856 seconds
#> fluxID 71 : slope was estimated on 851 points out of 857 seconds
#> fluxID 72 : slope was estimated on 845 points out of 853 seconds
#> fluxID 87 : slope was estimated on 859 points out of 860 seconds
#> fluxID 89 : slope was estimated on 848 points out of 849 seconds
# View(conc_fit)
<- flux_quality(
conc_flags slopes_df = conc_fit,
f_conc = CO2_dry,
force_discard = 72 # obviously a complete mismatch
)#>
#> Total number of measurements: 55
#>
#> ok 30 55 %
#> discard 21 38 %
#> zero 3 5 %
#> force_discard 1 2 %
#> start_error 0 0 %
#> no_data 0 0 %
#> force_ok 0 0 %
#> force_zero 0 0 %
#> force_lm 0 0 %
#> no_slope 0 0 %
# View(conc_flags)
flux_plot(
conc_flags,f_conc = CO2_dry,
print_plot = FALSE,
output = "pdfpages",
scale_x_datetime_args = list(
date_breaks = "10 min",
minor_breaks = "2 min",
date_label = "%e/%m \n %H:%M"
),f_plotname = "eosense4h10f",
f_ylim_upper = 650
)
Note: I found a bug in flux_calc, it is not dealing well with the pressure as a variable. It is fixed in fluxible v1.2.5 (dev version), if you are using the CRAN version (v1.2.2) you will need to set the pressure as a constant.
<- flux_calc(
fluxible_df slopes_df = conc_flags,
slope_col = f_slope_corr,
temp_air_col = air_temp,
setup_volume = 72, # not sure if correct, found on website
# setup_volume = 4.756,
plot_area = 0.21, # to check
# plot_area = 0.032,
# atm_pressure = 1,
atm_pressure = pressure,
conc_unit = "ppm",
flux_unit = "umol/m2/s",
cols_keep = "f_quality_flag"
|>
) rename(
fluxible_flux = "f_flux",
fluxible_slope = "f_slope_corr"
|>
) mutate(
f_datetime = f_datetime + 29329 # correcting the other way to match eosense
)#> Cutting data according to 'keep_arg'...
#> Averaging air temperature for each flux...
#> Creating a df with the columns from 'cols_keep' argument...
#> Calculating fluxes...
#> R constant set to 0.082057
#> Concentration was measured in ppm
#> Fluxes are in umol/m2/s
# View(fluxible_df)
saveRDS(fluxible_df, "compare_data/fluxible_df.rds")
Structure of fluxible_df:
#> tibble [55 × 8] (S3: tbl_df/tbl/data.frame)
#> $ f_quality_flag : chr [1:55] "discard" "ok" "ok" "ok" ...
#> $ f_fluxid : Factor w/ 113 levels "1","2","3","4",..: 45 4..
#> $ fluxible_slope : num [1:55] NA 0.023 0.0543 0.0564 0.0222 ...
#> $ f_temp_air_ave : num [1:55] 10.7 NaN 10.7 10.9 11 ...
#> $ f_atm_pressure_ave: num [1:55] 0.993 NaN 1.048 0.992 1.052 ...
#> $ f_datetime : POSIXct[1:55], format: "2024-12-11 20:37:33" ..
#> $ fluxible_flux : num [1:55] NA NaN 0.838 0.822 0.343 ...
#> $ f_model : chr [1:55] "linear" "linear" "linear" "linea"..
#> - attr(*, "fit_type")= chr "linear"