Skip to content

Commit 8887a2f

Browse files
committed
docs: add comprehensive toolbox documentation
The documentation was sparse and consisted only of README with installation instructions. This adds proper user guides, tutorials, and example plots to help scientists get started with the library. - Add quickstart guide with minimal examples - Add batch reactor guide covering all Batch class functionality - Add column transport guide covering all Column class functionality - Add tutorial: organic matter degradation (Roden 2008) - Add tutorial: sediment diagenesis with complex reaction network - Add GitHub Pages workflow for automatic deployment - Extract example plots from Jupyter notebooks - Remove outdated publishing.md
1 parent 9364b4d commit 8887a2f

12 files changed

Lines changed: 1107 additions & 8 deletions

.github/workflows/docs.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Deploy Documentation to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
paths:
8+
- 'docs/**'
9+
- '.github/workflows/docs.yml'
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: read
14+
pages: write
15+
id-token: write
16+
17+
concurrency:
18+
group: "pages"
19+
cancel-in-progress: false
20+
21+
jobs:
22+
deploy:
23+
environment:
24+
name: github-pages
25+
url: ${{ steps.deployment.outputs.page_url }}
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
31+
- name: Setup Pages
32+
uses: actions/configure-pages@v4
33+
34+
- name: Upload artifact
35+
uses: actions/upload-pages-artifact@v3
36+
with:
37+
path: 'docs'
38+
39+
- name: Deploy to GitHub Pages
40+
id: deployment
41+
uses: actions/deploy-pages@v4

docs/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# PorousMediaLab Documentation
2+
3+
PorousMediaLab is a Python toolbox for batch and 1D reactive transport modeling in porous media, designed for scientists without extensive computational backgrounds.
4+
5+
## Quick Links
6+
7+
| Document | Description |
8+
|----------|-------------|
9+
| [Quickstart](quickstart.md) | Get started in 5 minutes |
10+
| [Batch Guide](batch-guide.md) | Complete guide to 0D batch reactor simulations |
11+
| [Column Guide](column-guide.md) | Complete guide to 1D reactive transport |
12+
13+
## Tutorials
14+
15+
Step-by-step tutorials with real-world examples:
16+
17+
- [Organic Matter Degradation](tutorials/batch-roden.md) - Batch reactor modeling following Roden 2008
18+
- [Sediment Diagenesis](tutorials/sediment-column.md) - 1D column transport with complex reactions
19+
20+
## Features
21+
22+
- **Batch Module** - 0D closed-system reaction simulations
23+
- **Column Module** - 1D advection-diffusion-reaction equation solver
24+
- **Flexible Reactions** - Define rates using string expressions with numexpr
25+
- **pH Equilibrium** - Built-in acid-base chemistry calculations
26+
- **Henry Equilibrium** - Gas-liquid partitioning
27+
- **Calibration** - Parameter optimization against experimental data
28+
- **Visualization** - Built-in plotting methods
29+
30+
## Installation
31+
32+
```bash
33+
pip install porousmedialab
34+
```
35+
36+
For development:
37+
38+
```bash
39+
git clone https://github.com/biogeochemistry/PorousMediaLab
40+
cd PorousMediaLab
41+
poetry install
42+
```
43+
44+
## Citation
45+
46+
Igor Markelov (2020). Modelling Biogeochemical Cycles Across Scales: From Whole-Lake Phosphorus Dynamics to Microbial Reaction Systems. UWSpace. http://hdl.handle.net/10012/15513
47+
48+
## Links
49+
50+
- [GitHub Repository](https://github.com/biogeochemistry/PorousMediaLab)
51+
- [PyPI Package](https://pypi.org/project/porousmedialab/)
52+
- [Example Notebooks](https://github.com/biogeochemistry/PorousMediaLab/tree/master/examples)

docs/batch-guide.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# Batch Reactor Guide
2+
3+
The `Batch` class simulates 0-dimensional (0D) batch reactor experiments - closed systems where only reactions occur without spatial transport.
4+
5+
## Creating a Batch
6+
7+
```python
8+
from porousmedialab.batch import Batch
9+
10+
batch = Batch(tend=40, dt=1)
11+
```
12+
13+
**Parameters:**
14+
- `tend` (float): End time of simulation (in your chosen time units)
15+
- `dt` (float): Timestep for integration
16+
17+
## Adding Species
18+
19+
```python
20+
batch.add_species(name='O2', init_conc=0.2)
21+
batch.add_species(name='CH4', init_conc=0.001)
22+
batch.add_species(name='CO2', init_conc=0)
23+
```
24+
25+
**Parameters:**
26+
- `name` (str): Name of the chemical species (used in rate expressions)
27+
- `init_conc` (float): Initial concentration
28+
29+
## Defining Constants
30+
31+
Constants are parameters used in rate expressions:
32+
33+
```python
34+
batch.constants['k1'] = 0.1 # Rate constant
35+
batch.constants['Km'] = 0.001 # Half-saturation constant
36+
batch.constants['T'] = 25 # Temperature
37+
```
38+
39+
## Defining Rate Expressions
40+
41+
Rate expressions are strings evaluated using [numexpr](https://github.com/pydata/numexpr):
42+
43+
```python
44+
# First-order kinetics
45+
batch.rates['R1'] = 'k1 * A'
46+
47+
# Michaelis-Menten kinetics
48+
batch.rates['R2'] = 'Vmax * S / (Km + S)'
49+
50+
# Multiple terms
51+
batch.rates['R3'] = 'k1 * A * B / (Km + B)'
52+
53+
# Inhibition term
54+
batch.rates['R4'] = 'k1 * A * Km_inh / (Km_inh + I)'
55+
```
56+
57+
**Available operators:** `+`, `-`, `*`, `/`, `**` (power)
58+
59+
**Available functions:** `exp`, `log`, `log10`, `sqrt`, `sin`, `cos`, `tan`, `abs`, `where`
60+
61+
## Setting dcdt (Time Derivatives)
62+
63+
Define how each species concentration changes over time:
64+
65+
```python
66+
# Simple consumption and production
67+
batch.dcdt['A'] = '-R1'
68+
batch.dcdt['B'] = 'R1'
69+
70+
# Multiple reactions affecting one species
71+
batch.dcdt['C'] = 'R1 - R2 + 0.5 * R3'
72+
73+
# Stoichiometric coefficients
74+
batch.dcdt['O2'] = '-2 * R1 - 4 * R2'
75+
```
76+
77+
## Running the Simulation
78+
79+
```python
80+
batch.solve(verbose=True)
81+
```
82+
83+
**Parameters:**
84+
- `verbose` (bool): If `True`, prints progress and time estimates
85+
86+
## Accessing Results
87+
88+
Results are stored in species dictionaries:
89+
90+
```python
91+
# Get concentration time series (shape: [1, num_timesteps])
92+
conc = batch.A.concentration
93+
94+
# Get final concentration
95+
final = batch.A.concentration[0, -1]
96+
97+
# Get time array
98+
time = batch.time
99+
100+
# Plot concentration vs time
101+
import matplotlib.pyplot as plt
102+
plt.plot(batch.time, batch.A.concentration[0])
103+
```
104+
105+
## Plotting Methods
106+
107+
Built-in plotting methods:
108+
109+
```python
110+
# Plot single species
111+
batch.plot('A')
112+
113+
# Plot all species
114+
batch.plot_profiles()
115+
116+
# Plot reaction rates
117+
batch.plot_rates()
118+
119+
# Plot rate of change (delta)
120+
batch.plot_deltas()
121+
```
122+
123+
## Saving Results
124+
125+
Save results to HDF5 format:
126+
127+
```python
128+
batch.save_results_in_hdf5()
129+
```
130+
131+
This creates `results.h5` containing:
132+
- `time`: Time array
133+
- `concentrations`: All species concentrations
134+
- `estimated_rates`: Calculated rates
135+
- `parameters`: Constants used
136+
137+
## Advanced: Henry Equilibrium
138+
139+
For gas-liquid partitioning:
140+
141+
```python
142+
# Add both aqueous and gas species
143+
batch.add_species(name='CO2_aq', init_conc=0.001)
144+
batch.add_species(name='CO2_gas', init_conc=0)
145+
146+
# Set Henry equilibrium (Hcc is dimensionless Henry constant)
147+
batch.henry_equilibrium(aq='CO2_aq', gas='CO2_gas', Hcc=0.83)
148+
```
149+
150+
## Advanced: Acid-Base Equilibrium
151+
152+
For pH-dependent systems:
153+
154+
```python
155+
# Add carbonate species
156+
batch.add_species(name='H2CO3', init_conc=0.001)
157+
batch.add_species(name='HCO3', init_conc=0.01)
158+
batch.add_species(name='CO3', init_conc=0.0001)
159+
160+
# Define acid with pKa values
161+
batch.add_acid(
162+
species=['H2CO3', 'HCO3', 'CO3'],
163+
pKa=[6.35, 10.33],
164+
charge=0 # Charge of fully protonated form
165+
)
166+
167+
# Add non-dissociating ion
168+
batch.add_species(name='Na', init_conc=0.1)
169+
batch.add_ion(name='Na', charge=1)
170+
171+
# Create the acid-base system
172+
batch.create_acid_base_system()
173+
```
174+
175+
After `create_acid_base_system()`, a `pH` species is automatically created and tracked.
176+
177+
## Complete Example
178+
179+
```python
180+
from porousmedialab.batch import Batch
181+
182+
# Create batch reactor
183+
batch = Batch(tend=40, dt=1)
184+
185+
# Add species
186+
batch.add_species(name='OM', init_conc=0.01) # Organic matter
187+
batch.add_species(name='O2', init_conc=0.2) # Oxygen
188+
batch.add_species(name='CO2', init_conc=0) # Carbon dioxide
189+
190+
# Set constants
191+
batch.constants['k'] = 0.5 # Degradation rate
192+
batch.constants['Km'] = 0.02 # Half-saturation
193+
194+
# Define rate
195+
batch.rates['R_deg'] = 'k * OM * O2 / (Km + O2)'
196+
197+
# Set time derivatives
198+
batch.dcdt['OM'] = '-R_deg'
199+
batch.dcdt['O2'] = '-R_deg'
200+
batch.dcdt['CO2'] = 'R_deg'
201+
202+
# Run and plot
203+
batch.solve()
204+
batch.plot_profiles()
205+
```
206+
207+
## Tips
208+
209+
1. **Timestep selection**: Start with a larger `dt` and decrease if you see numerical instabilities
210+
2. **Units**: Be consistent with units throughout (e.g., mol/L for concentrations, 1/day for rates)
211+
3. **Debugging**: Use `verbose=True` to see simulation progress
212+
4. **Rate expressions**: Ensure all variables in rate expressions are defined as species or constants

0 commit comments

Comments
 (0)