ODS Calculation Suite — v3.8.0 Author: Hoda Jafari | MIT License
A Streamlit-based web application for oxidative desulfurization (ODS) kinetic analysis. Designed for PhD-level catalysis research — covers nonlinear kinetic fitting, activity metrics, residual diagnostics, Arrhenius analysis, and condition comparison.
Developed and validated for graphene-like metal-free catalysts derived from spent coffee grounds, covering thermal ODS, photocatalytic (PODS/UV), and electrochemical (ECODS) conditions.
git clone https://github.com/Hj1308/CatLab-Tools.git
cd CatLab-Tools
pip install -r requirements.txt
streamlit run app_ods.pyAlternatively, install the package with its app extras (or an exact reproduction via the lock file):
pip install -e .[app]
# or, for an exact reproduction of the verified dependency set:
pip install -r requirements-lock.txt| Tab | Module | Description |
|---|---|---|
| 1 | Kinetic Fitting | Fit 9 kinetic models, AICc model selection, k±SE, r₀, t½ |
| 2 | Linearization | Linear transforms (1/C vs t, ln(C₀/C) vs t) with best-model summary |
| 3 | Removal Efficiency | Desulfurization efficiency (%) vs time + bar chart |
| 4 | TON / TOF | Option A: site-based (metal catalysts) · Option B: mass-normalized (carbon-based) |
| 5 | Parameter Effect | Simulate X%, k, t½ vs concentration, mass, temperature, O/S ratio |
| 6 | Oxidant Efficiency | H₂O₂ utilisation efficiency (η%) |
| 7 | Condition Comparison | Side-by-side k/t½/r₀ across conditions |
| 8 | Arrhenius Analysis | Multi-temperature Ea & A with 95% confidence intervals |
| 9 | Residual Diagnostics | Shapiro-Wilk, runs test, Q-Q plot, outlier detection |
Best model selected automatically by AICc (small-sample corrected AIC) with parsimony rule. All models fitted by nonlinear least squares with C₀ locked.
| Model | Integrated Rate Law | t½ | Class |
|---|---|---|---|
| Zero-order | Simplified | ||
| Pseudo-first-order | Simplified | ||
| Pseudo-first (initial drop) | Semi-empirical | ||
| Pseudo-second-order | Simplified | ||
| Elovich | Phenomenological | ||
| Langmuir-Hinshelwood |
|
Mechanistic | |
| Power-Law | analytical | Empirical | |
| Avrami | — | Phenomenological | |
| Double-Exponential | — | Phenomenological |
Eley-Rideal was removed in v3.7.0: under excess oxidant its rate law is Pseudo-first-order with an extra unidentifiable parameter.
Auto-saturation detection: Tab 1 offers a user-adjustable fractional-uptake cutoff after Simonin (2016): any point whose removal exceeds a chosen fraction of the final/equilibrium removal value is excluded before fitting. Simonin originally proposed an 85% cutoff to reduce artificial pseudo-second-order dominance in simple two-model (PFO/PSO) adsorption studies.
Default = 1.0 (disabled). Two independent reasons:
- Simonin's criterion targets linearised PFO/PSO fitting, where near-equilibrium points align spuriously in a t/q vs t plot and inflate PSO's r². CatLab fits non-linearly, so this failure mode does not arise.
- Simonin's F(t) = q(t)/q_e requires an independently measured equilibrium capacity. The current implementation substitutes the last observed point, which is not equivalent.
Internal validation on synthetic ground-truth curves (8 archetypes × 200 seeds = 1600 fits, seed 20260812) shows that enabling the cutoff degrades mechanistic-model recovery from 55.9% to 36.1% and raises false-PSO selection on mechanistic data from 0.0% to 2.1%. Because MIN_FIT_POINTS = 6 and typical ODS datasets have 7 points, all cutoff values below 1.0 produce an identical 6-point retained set — the control is effectively binary, not continuous.
On datasets with enough points for the cutoff to act as a genuine continuum (more than MIN_FIT_POINTS + 1), users studying pure adsorption kinetics with only PFO/PSO in play may lower the slider. Note that this remains a last-point proxy, not Simonin's F(t) = q(t)/q_e; see Simonin (2016), Chem. Eng. J., DOI 10.1016/j.cej.2016.04.079.
Both critiques of PSO target linearised fitting. Simonin (2016) shows that near-equilibrium points align spuriously in a t/q vs t plot and inflate PSO's r². Kostoglou & Karapantsios (2022, Colloids Interfaces 6, 55, DOI 10.3390/colloids6040055) reach the same conclusion independently: the apparent success of the linearised PSO form is artificial, arising from overweighting the large-t behaviour of q, and can make PSO appear better even than sophisticated mechanistic models. Both papers recommend non-linear fitting; CatLab fits non-linearly, so neither critique applies.
CatLab also follows Kostoglou & Karapantsios' first recommendation by design: it works with removal % (a function of the directly measured C/C₀) rather than the calculated adsorbed mass q, avoiding propagation of catalyst-mass and volume uncertainty into the fitted data.
Standard Error from the curve_fit covariance matrix:
Initial reaction rate r₀:
| Model | r₀ formula |
|---|---|
| Zero-order | |
| Pseudo-first-order | |
| Pseudo-second-order | |
| Elovich | |
| L-H | |
| Power-Law |
TON = n_substrate_converted / n_active_sites (dimensionless)
TOF (h⁻¹) = TON / t_reaction
Active site density from direct measurement (TPD/TPR/chemisorption) or BET + material-type presets.
For graphene-like, N/B-doped carbon, BCN, and similar materials, defining "active sites" is ambiguous. Mass-normalized TOF is the standard in the ODS literature for metal-free catalysts.
TOF_mass (mmol·g⁻¹·min⁻¹) = n_DBT_removed / (m_cat × t_reaction)
TOF_BET (mmol·m⁻²·min⁻¹) = TOF_mass / BET_area
BET from Excel: Add a sheet named Catalyst_Properties to your data file:
| Catalyst | BET (m²/g) | Notes |
|---|---|---|
| g-SiC | 150 | N₂ adsorption, 77 K |
| g-NSiC | 250 |
The app reads BET values automatically and pre-fills the input fields.
Upload one kinetic data file per temperature. The app fits each dataset, extracts k(T), then fits:
k(T) = A · exp(−Eₐ / RT)
Reports Eₐ and A with 95% confidence intervals.
⚠️ For L-H and Power-Law models, k is a composite parameter — Eₐ is apparent. Use a single fixed model (e.g. Pseudo-second-order) for a valid Arrhenius plot.
| Feature | ppmS | ppm / mg/L |
|---|---|---|
| What is measured | Mass of sulfur atom | Mass of the pollutant molecule |
| MW used | MW_S = 32.06 g/mol (auto-applied) | MW of compound (e.g. DBT = 184.26 g/mol) |
| Default definition | mg S / L fuel (volumetric) | mg compound / L solution |
C₀ [mol/L] = C [mg S/L] / (MW_S [g/mol] × 10³)
Example: 250 ppmS → 250 / 32.06 / 1000 = 7.798 × 10⁻³ mol/L
Mass basis (advanced): For true mass fraction (mg S / kg fuel, e.g. XRF or ASTM D5453), switch to Mass basis in the sidebar — fuel density ρ (g/mL) is then applied.
| Unit | Conversion basis | MW Required? |
|---|---|---|
| ppmS | mg S / L fuel → mol/L via MW_S (volumetric default) | ❌ |
| ppm / mg/L | mg compound / L → mol/L via MW_compound | ✅ |
| mmol/L | Direct × 10⁻³ | ❌ |
| mol/L | Direct | ❌ |
| g/L | ÷ MW_compound → mol/L | ✅ |
| Parameter | Value | Unit |
|---|---|---|
| Initial sulfur concentration | 250 | ppmS (mg S / L fuel, volumetric) |
| Model solvent | n-Heptane | ρ = 0.684 g/mL |
| C₀ (mol/L) | 7.798 × 10⁻³ | 250 / 32.06 / 1000 |
| O/S molar ratio | 0.5 |
Required columns in Raw_Data sheet:
Time (min)— reaction time- One or more catalyst columns:
CatName Removal (%)
Time must be in minutes.
Optional sheet — Catalyst_Properties (for Tab 4 Option B):
Catalyst— must match catalyst column namesBET (m²/g)— BET surface area
Download the advanced template from Tab 1 to get a pre-filled Excel file.
CatLab-Tools/
├── app_ods.py # Main Streamlit app (v3.8.0)
├── requirements.txt # numpy, pandas, matplotlib, scipy, openpyxl, streamlit
├── CHANGELOG.md # Full version history
├── CITATION.cff # Citation metadata (DOI: 10.5281/zenodo.20753373)
├── catlab/ # Core Python library modules
├── examples/ # Example datasets
├── tests/ # Unit tests
└── .github/ # GitHub Actions / workflows
- Barghi, S.H. et al. ACS Omega 2025, 10, 15947. DOI: 10.1021/acsomega.4c06722
- Dhir, S. et al. J. Hazard. Mater. 2009, 161, 1360. DOI: 10.1016/j.jhazmat.2008.04.099
- Sengupta, A. et al. Ind. Eng. Chem. Res. 2012, 51, 147. DOI: 10.1021/ie2024068
- Safa, M. et al. Fuel 2019, 239, 24. DOI: 10.1016/j.fuel.2018.10.147
- Burnham, K.P.; Anderson, D.R. Model Selection and Multimodel Inference, 2nd ed.; Springer, 2002. (AICc criterion)
- Simonin, J.-P. Chem. Eng. J. 2016, 300, 254. DOI: 10.1016/j.cej.2016.04.079 (85% fractional-uptake cutoff to reduce artificial PSO dominance in PFO/PSO adsorption studies)
- Kostoglou, M.; Karapantsios, T.D. Colloids Interfaces 2022, 6, 55. DOI: 10.3390/colloids6040055 (broader critique of pseudo-second-order artifacts — why the cutoff does not transfer to a multi-model portfolio)
- Grzesik, M.; Szymonski, K. Ind. Eng. Chem. Res. 2021, 60, 8957. DOI: 10.1021/acs.iecr.1c01663 (comment on PSO misuse)
| Repo | Purpose |
|---|---|
| BET_analyser | BET, BJH, T-Plot, isotherm & hysteresis |
| EISForge | EIS analysis + ML |
| sem-particle-analyzer | SEM particle sizing |
| Raman-analysis | Raman spectroscopy toolkit |
| Version | Key Changes |
|---|---|
| v3.8.0 | New model "Pseudo-first (initial drop)" (fast initial step + first order; 9 models); Tab 1 warns when fewer than 6 points; Tab 2 flags linearisation intercepts that contradict the model; CSV uploads work in every tab; end-to-end UI tests, ruff formatting |
| v3.7.0 | t=0 anchor point no longer counted as data (R², AICc, residual stats); exact L-H solution (Lambert W); Double-Exponential k1 always fast; Eley-Rideal removed (8 models); warning for non-minute time columns; fractional-time exclusion fixed; pyproject.toml |
| v3.6.0 | One model-selection rule (AICc) across package API and app; initial-rate TOF in Tab 4; Tab 2 R² shown as a diagnostic, no ranking; exact reporting of fractional excluded times |
| v3.5.5 | AICc counts σ² as a parameter (K = p+1); Arrhenius CI uses the t-distribution; MIN_FIT_POINTS = 6; Akaike weights |
| v3.5.4 | Package kinetics fitting moved from linearised regression to the shared non-linear engine |
| v3.5.3 | Power-Law n>1 bug fix; Eley-Rideal excluded from auto-selection; Arrhenius composite-k warning; CSV auto-separator; Tab 4 Option B mass-normalized TOF for carbon catalysts |
| v3.5.2 | Auto-saturation detection (8%/15% thresholds); per-catalyst point exclusion in Tab 1; linearized plots based on best model |
| v3.5.1 | Power-Law numerical stability; Tab 8 savefig fix; model classification in assumptions |
| v3.5.0 | ppmS volumetric default (no density); AICc model selection; Pseudo-second-order rename; residual diagnostics ddof fix |
| v3.4 | Tab 8 Arrhenius multi-temperature; Tab 9 residual diagnostics |
| v3.3 | L-H t½ analytical fix; centralised data loader; shared file uploader |
| v3.2 | ppmS/ppm dual C₀ display; solvent selector; oxidant efficiency tab |
| v3.0 | L-H model; k±SE; r₀; Power-Law; Eley-Rideal; Avrami; Double-Exponential |
Full changelog: CHANGELOG.md
If you use CatLab-Tools in your research, please cite the version you used:
Jafari, H. (2026). CatLab-Tools: Oxidative Desulfurization Kinetics & Analysis Suite (v3.8.0). Zenodo. DOI: 10.5281/zenodo.23112259
| DOI | Resolves to |
|---|---|
| 10.5281/zenodo.23112259 | v3.8.0 only — cite this for results produced with v3.8.0 |
| 10.5281/zenodo.23091566 | v3.7.0 only — cite this for results produced with v3.7.0 |
| 10.5281/zenodo.20753373 | All versions (always the latest release) |
Results from v3.7.0 onward differ slightly from earlier versions (the t=0 point is no longer counted as data, and L-H uses its exact solution); cite the version-specific DOI so the numbers can be reproduced.
MIT License. See LICENSE for full terms.
Copyright (c) 2026 Hoda Jafari