Modeling Adsorption Isotherms with AdsorpR

๐Ÿ“ฆ Introduction

The AdsorpR package provides functions for modeling four classical adsorption isotherms:

  • Langmuir (monolayer adsorption)
  • Freundlich (heterogeneous surfaces)
  • BET (multilayer adsorption)
  • Temkin (linear decrease of adsorption energy)

These models are commonly used in environmental and chemical engineering studies to describe sorption mechanisms of contaminants onto solid adsorbents.

๐Ÿงช Sample Dataset

We demonstrate model usage using a simple example dataset representing equilibrium concentration (Ce) and the amount adsorbed (Qe):

Ce <- c(1, 2, 3, 4, 5)
Qe <- c(0.8, 1.5, 2.1, 2.6, 2.9)

๐Ÿ“ Langmuir Isotherm

result_l <- langmuir_model(Ce, Qe)
print(result_l[1:2])        # Qmax and KL
#> $`Langmuir Qmax (mg/g)`
#>       Ce 
#> 8.669989 
#> 
#> $`Langmuir KL (L/mg)`
#>        Ce 
#> 0.1040153
print(result_l$`Model Summary`)
#> 
#> Call:
#> lm(formula = Ce_by_Qe ~ Ce)
#> 
#> Residuals:
#>         1         2         3         4         5 
#>  0.025780 -0.006227 -0.026329 -0.031780  0.038556 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)  1.10888    0.03778   29.35 8.69e-05 ***
#> Ce           0.11534    0.01139   10.12  0.00205 ** 
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 0.03602 on 3 degrees of freedom
#> Multiple R-squared:  0.9716, Adjusted R-squared:  0.9621 
#> F-statistic: 102.5 on 1 and 3 DF,  p-value: 0.002052
result_l$Plot
#> `geom_smooth()` using formula = 'y ~ x'

๐Ÿ“ Freundlich Isotherm

result_f <- freundlich_model(Ce, Qe)
print(result_f[1:2])        # Kf and n
#> $`Freundlich Kf`
#> (Intercept) 
#>   0.8265344 
#> 
#> $`Freundlich n`
#>   log_Ce 
#> 1.228491
print(result_f$`Model Summary`)
#> 
#> Call:
#> lm(formula = log_Qe ~ log_Ce)
#> 
#> Residuals:
#>         1         2         3         4         5 
#> -0.014171  0.013790  0.016579  0.007632 -0.023829 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) -0.08274    0.01818  -4.551 0.019877 *  
#> log_Ce       0.81401    0.03759  21.653 0.000216 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 0.02075 on 3 degrees of freedom
#> Multiple R-squared:  0.9936, Adjusted R-squared:  0.9915 
#> F-statistic: 468.8 on 1 and 3 DF,  p-value: 0.0002156
result_f$Plot
#> `geom_smooth()` using formula = 'y ~ x'

๐Ÿ“ BET Isotherm

result_b <- bet_model(Ce, Qe)
print(result_b[1:2])        # Qm and Cb
#> $`BET Qm (mg/g)`
#>    BET_x 
#> 0.346352 
#> 
#> $`BET Cb`
#>     BET_x 
#> -3.023631
print(result_b$`Model Summary`)
#> 
#> Call:
#> lm(formula = BET_y ~ BET_x)
#> 
#> Residuals:
#>        1        2        3        4        5 
#>  0.53410 -0.06129 -0.56939 -0.81374  0.91032 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)  
#> (Intercept)  -0.9549     0.8783  -1.087   0.3565  
#> BET_x         3.8421     1.4566   2.638   0.0778 .
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 0.8375 on 3 degrees of freedom
#> Multiple R-squared:  0.6987, Adjusted R-squared:  0.5983 
#> F-statistic: 6.958 on 1 and 3 DF,  p-value: 0.0778
result_b$Plot
#> `geom_smooth()` using formula = 'y ~ x'

๐Ÿ“ Temkin Isotherm

result_t <- temkin_model(Ce, Qe)
print(result_t[1:2])        # A and B
#> $`Temkin A`
#> (Intercept) 
#>    1.712047 
#> 
#> $`Temkin B`
#>    ln_Ce 
#> 1.324248
print(result_t$`Model Summary`)
#> 
#> Call:
#> lm(formula = adjusted_Qe ~ ln_Ce)
#> 
#> Residuals:
#>      1      2      3      4      5 
#>  217.9 -321.9 -165.7  129.2  140.4 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)   1764.1      234.5   7.522 0.004870 ** 
#> ln_Ce         3280.9      210.6  15.577 0.000575 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 267.7 on 3 degrees of freedom
#> Multiple R-squared:  0.9878, Adjusted R-squared:  0.9837 
#> F-statistic: 242.7 on 1 and 3 DF,  p-value: 0.0005749
result_t$Plot
#> `geom_smooth()` using formula = 'y ~ x'

๐Ÿ” Non-linear Isotherm Modeling

Non-linear Langmuir

Ce <- c(1, 2, 4, 6, 8, 10)
Qe <- c(0.9, 1.6, 2.3, 2.7, 2.9, 3.0)
result <- nonlinear_langmuir(Ce, Qe)
print(result$`Langmuir Qmax (mg/g)`)
#>     Qmax 
#> 4.000269
print(result$`Langmuir KL (L/mg)`)
#>        KL 
#> 0.3262891
print(result$AIC)
#> [1] -12.78784
print(result$`Pseudo R2`)
#> [1] 0.9955326
print(result$Plot)
#> `geom_smooth()` using formula = 'y ~ x'

Non-linear Freundlich

Ce <- c(0.5, 1, 2, 4, 6, 8)
Qe <- c(0.3, 0.8, 1.6, 2.4, 2.9, 3.2)
result <- nonlinear_freundlich(Ce, Qe)
print(result$`Freundlich Kf`)
#>        Kf 
#> 0.9214474
print(result$`Freundlich n`)
#>        n 
#> 1.598388
print(result$AIC)
#> [1] 3.105419
print(result$`Pseudo R2`)
#> [1] 0.9680789
print(result$Plot)
#> `geom_smooth()` using formula = 'y ~ x'
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : Chernobyl! trL>n 6
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : Chernobyl! trL>n 6
#> Warning in sqrt(sum.squares/one.delta): NaNs produced

Non-linear BET

Ce <- c(1, 2.5, 4, 5.5, 7)
Qe <- c(0.4, 1.0, 1.7, 2.3, 2.7)
result <- nonlinear_bet(Ce, Qe)
#> Warning in nls(Qe ~ (Qm * Cb * Ce)/((Cs - Ce) * (1 + (Cb - 1) * Ce/Cs)), : step
#> factor 5.82077e-11 reduced below 'minFactor' of 1e-10
print(result$`BET Qm (mg/g)`)
#>        Qm 
#> 0.2899103
print(result$`BET Cb`)
#>           Cb 
#> 836531218564
print(result$AIC)
#> [1] 18.29629
print(result$`Pseudo R2`)
#> [1] 0.02393608
print(result$Plot)
#> `geom_smooth()` using formula = 'y ~ x'
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : span too small.  fewer data values than degrees of freedom.
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : pseudoinverse used at 0.97
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : neighborhood radius 3.03
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : reciprocal condition number 0
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : There are other near singularities as well. 9.1809

Non-linear Temkin

Ce <- c(0.5, 1.5, 3, 4.5, 6)
Qe <- c(0.7, 1.3, 2.0, 2.4, 2.7)
result <- nonlinear_temkin(Ce, Qe)
print(result$`Temkin A`)
#>       AT 
#> 4.126122
print(result$`Temkin B`)
#>        bT 
#> 0.8129749
print(result$AIC)
#> [1] -2.230427
print(result$`Pseudo R2`)
#> [1] 0.9788445
print(result$Plot)
#> `geom_smooth()` using formula = 'y ~ x'
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : span too small.  fewer data values than degrees of freedom.
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : pseudoinverse used at 0.4725
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : neighborhood radius 2.5275
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : reciprocal condition number 0
#> Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,
#> : There are other near singularities as well. 9.1658

๐Ÿ“ Conclusion

The AdsorpR package offers a clean and structured way to fit adsorption isotherm models and visualize results using ggplot2. It is useful for:

  • Environmental monitoring studies
  • Sorption modeling of nutrients and pollutants in soil
  • Research on water/soil remediation