Date: 2026-09-02

# Modeling Adsorption Isotherms with AdsorpR

#### Jajati Mandal

#### Sandipan Samanta

#### 2026-09-02

## 📦 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.3091857
    print(result$`BET Cb`)
    #>           Cb
    #> 6.875806e+18
    print(result$AIC)
    #> [1] 18.24174
    print(result$`Pseudo R2`)
    #> [1] 0.03452733
    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