This project sets up a compartmental ODE model. It aims to simulate the way bacterial populations shift and grow when facing antibiotic pressure. The model builds in suppression effects that depend on the dose given. It also looks into various dosing approaches by running four organized simulations.
Key Features:
- ODE-based bacterial growth model with antibiotic pharmacodynamics (PK/PD)
- Configurable dosing strategies (constant and pulsed)
- Parameter fitting via least-squares optimization
- Publication-quality visualizations
- Modular, documented R code architecture
.
βββ src/ # R source code
β βββ main.R # Pipeline orchestration
β βββ model.R # ODE definition
β βββ simulate.R # Data generation
β βββ fit.R # Parameter fitting
β βββ visualize.R # Plotting
β βββ io.R # Config & I/O
βββ config/
β βββ sim_params.yaml # Parameters
βββ figures/ # Output plots (8 files)
βββ results/ # Output metrics (4 CSV files)
βββ data/ # User data (optional)
βββ README.md
ODE Equation:
dN/dt = rΒ·NΒ·(1 - N/K) - k_max Β· [A(t)^h / (EC50^h + A(t)^h)] Β· N
Parameters:
- N(t): Bacterial density (cells)
- r: Growth rate (hrβ»ΒΉ)
- K: Carrying capacity (cells)
- A(t): Antibiotic concentration (ΞΌg/mL, time-dependent)
- k_max: Maximum kill rate (hrβ»ΒΉ)
- EC50: Half-maximal effect concentration (ΞΌg/mL)
- h: Hill coefficient (sigmoidal slope)
Dosing Modes:
- Constant: A(t) = Aβ throughout
- Pulse: Square pulses every N hours for M-hour duration
| Run | Configuration | EC50 (ΞΌg/mL) | Hill (h) | Best Conc | AUC | Key Finding |
|---|---|---|---|---|---|---|
| 1 | Constant, fit EC50+h | 2.43 | 1.17 | 20 | 1.06e+06 | Baseline reference |
| 2 | Pulse (12h), fit EC50+h | 2.43 | 1.17 | 20 | 1.06e+06 | Clinical relevance |
| 3 | Constant, fit EC50 only | 2.00 | 1.50* | 20 | 2.31e+10 | Parameter sensitivity |
| 4 | Extended [0-50], fit EC50+h | 2.00 | 1.50 | 50 | 9.23e+05 | Saturation effects |
*Hill coefficient fixed at 1.50
Configuration: Constant dosing [0β20 ΞΌg/mL], both parameters fitted
Finding: EC50 = 2.43 ΞΌg/mL; Hill = 1.17
Establishes standard dose-response curve. Lower Hill suggests weak cooperativity.
Interpretation: Antibiotic effect is relatively linear rather than sigmoidal.
Configuration: Pulsed dosing (12h interval, 2h duration), both parameters fitted
Finding: EC50 = 2.43 ΞΌg/mL; Hill = 1.17 (identical to Run 1)
AUC remains consistent despite intermittent dosing.
Interpretation: Clinical relevanceβsimulates realistic antibiotic therapy. Bacterial rebound between doses visible in time-courses, explaining resistance development risk.
Configuration: Constant dosing, EC50 fitted only (Hill fixed at 1.50)
Finding: EC50 = 2.00 ΞΌg/mL; AUC = 2.31e+10 (much higher)
EC50 shifts when Hill is constrained.
Interpretation: Demonstrates parameter interdependence. When prior knowledge constrains Hill, EC50 adjusts to compensate. Shows importance of data quality for reliable parameter estimation.
Configuration: Extended range [0β50 ΞΌg/mL], both parameters fitted
Finding: EC50 = 2.00 ΞΌg/mL; Best concentration shifts to 50 ΞΌg/mL; AUC = 9.23e+05
Model saturates at high dosesβdiminishing returns beyond 20 ΞΌg/mL.
Interpretation: Identifies safe and effective dosing windows. High doses don't provide additional benefit, suggesting toxicity thresholds should be considered in clinical practice.
- X-axis: Time (hours)
- Y-axis: Bacterial density (CFU/mL, log scale)
- Panels: One per antibiotic concentration
- Pattern: Higher concentrations show stronger suppression
- X-axis: Antibiotic concentration (ΞΌg/mL)
- Y-axis: AUC (area under curve β cumulative bacterial exposure )
- Red line: EC50 mark (half-maximal effect)
- Sigmoid curve: S-shaped dose-response
| Column | Meaning |
|---|---|
| AUC | Total bacterial burden (lower = better) |
| max_density | Peak population size |
| time_to_50pct_reduction | Hours to 50% suppression |
| estimated_EC50 | Fitted potency |
| estimated_h | Fitted cooperativity |
# Clone repository
git clone https://github.com/jobinjohn24/bacterial-growth-simulation.git
cd bacterial-growth-simulation
# Install dependencies in R
install.packages(c("yaml", "deSolve", "ggplot2"))Rscript src/main.ROutput: Plots in figures/ and metrics in results/
Edit config/sim_params.yaml:
A_levels: [0, 0.5, 1.5, 3, 5] # Custom rangedose_schedule: "pulse"
pulse_interval: 8 # Every 8 hours
pulse_duration: 1 # For 1 hourPlace CSV in data/growth.csv with columns:
time, concentration, density
fit_free: ["EC50"] # Fit only EC50
fit_free: ["r", "K"] # Fit growth parameters
fit_free: ["EC50", "h"] # Fit potency & cooperativitytmax: 72 # 72 hours instead of 48noise_sd: 1.0e7 # Increase measurement noise






