Skip to content

Commit 7de493a

Browse files
author
Daniel Precioso, PhD
committed
Refine assignment subtitles for clarity across multiple modules
1 parent 1db3c03 commit 7de493a

11 files changed

Lines changed: 423 additions & 177 deletions

File tree

modules/agent-based-modeling/assignment.qmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Assignment"
3-
subtitle: "Session 8: Agent-Based Traffic"
3+
subtitle: "Agent-Based Traffic"
44
format: html
55
---
66

modules/cellular-automata/assignment.qmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Assignment"
3-
subtitle: "Session 7: Cellular Automata"
3+
subtitle: "Cellular Automata"
44
format: html
55
---
66

modules/ode-1d/assignment.qmd

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,67 @@
11
---
22
title: "Assignment"
3-
subtitle: "ODEs in 1D: Spruce Budworm model"
3+
subtitle: "Spruce Budworm App"
44
format: html
55
---
66

7-
Implement the complete Streamlit application for the **Spruce Budworm model** as described [here](spruce-budworm.qmd), following the sections from [Implementing the ODE Function](spruce-budworm.qmd#sec-implementing-ode-function) through [Building the Streamlit Application](spruce-budworm.qmd#sec-streamlit-application) [@strogatz2024nonlinear]. Ensure that all functions are correctly defined and integrated into the app. Test the application thoroughly to confirm that it behaves as expected.
7+
This assignment turns the Session 1 workflow into a complete mini-project. The spruce budworm model combines a scalar ODE, equilibrium structure, numerical integration, and an interactive front end [@strogatz2024nonlinear].
88

9-
Answer at least three of the exploration questions from [Exploration Questions](spruce-budworm.qmd#sec-exploration-questions) and document your findings in a brief report (1-2 pages). You are encouraged to use LaTeX here. Include graphs demonstrating different behaviors observed during your exploration.
9+
You can follow the guide here:
1010

11-
If you want to go the extra mile, here are some additional challenges you can tackle:
11+
[Spruce Budworm Model](spruce-budworm.qmd){.btn .btn-primary}
1212

13-
- Create a GitHub repository for your project and push your code there. You can include the text of your report in the repository as well.
14-
- Deploy your Streamlit app using Streamlit Cloud or another hosting service. Share the link in your report.
15-
- Implement some of the advanced features mentioned in [Building the Streamlit Application](spruce-budworm.qmd#sec-streamlit-application).
16-
- Instead of using SciPy's built-in ODE solver, implement your own simple Euler or Runge-Kutta integrator and compare results.
13+
## Summary of Goals
14+
15+
Your submission should show that you can do three things:
16+
17+
1. Implement the spruce budworm model and its supporting visualizations.
18+
2. Build an interactive app that evolves the dynamics correctly.
19+
3. Interpret the resulting equilibria, bistability, and hysteresis behavior.
20+
21+
::: {.callout-note}
22+
## Submission
23+
24+
Submit two files:
25+
26+
1. The Python code for your Streamlit app and any helper module you created.
27+
2. A short report, 1 to 2 pages, that answers the exploration questions you chose.
28+
:::
29+
30+
## Required
31+
32+
1. Implement the `spruce_budworm()` right-hand side and the plotting helpers described in [spruce-budworm.qmd](spruce-budworm.qmd).
33+
2. Build a Streamlit app that includes the phase portrait, the time-series plot, and an “Evolve Forward” control.
34+
3. Use `st.session_state` so the simulation persists across interactions.
35+
4. Answer at least three exploration questions from [Exploration Questions](spruce-budworm.qmd#sec-exploration-questions).
36+
5. Include figures that support your interpretation.
37+
38+
## Short Discussion
39+
40+
Your report should address questions such as:
41+
42+
1. How many equilibria appear for the parameter values you explored?
43+
2. Did different initial conditions converge to different long-run states?
44+
3. Did you observe signs of hysteresis or threshold behavior?
45+
46+
## Optional Extensions
47+
48+
- Create a GitHub repository for your project and include the report.
49+
- Deploy the Streamlit app and share the link.
50+
- Add a reset button or multiple trajectories.
51+
- Implement Euler or Runge–Kutta yourself and compare with SciPy.
1752

1853
## Tips for Success
1954

20-
- **Start simple:** Get [Implementing the ODE Function](spruce-budworm.qmd#sec-implementing-ode-function) working first, then build up.
21-
- **Test incrementally:** Verify each function works before moving to the next.
22-
- **Use the reference:** The provided code (and additional documentation) is there to help you understand the structure.
23-
- **Experiment:** Try different parameter values and see what happens.
24-
- **Collaborate:** Discuss with your teammates, divide the work if needed. You can also work separately and then compare your implementations.
25-
- **Ask questions:** If you're stuck, ask for help!
55+
- Start with the ODE and the static plots before you build the app.
56+
- Test each helper function separately.
57+
- Keep the simulation state logic simple before adding extra features.
58+
- Use the reference script to compare shapes and parameter behavior.
59+
- Focus on interpretation, not only on getting the app to run.
60+
61+
::: {.callout-tip}
62+
Reference code is available in [amlab/odes_1d/spruce_budworm.py](../../amlab/odes_1d/spruce_budworm.py).
63+
:::
2664

2765
\vspace{1cm}
2866

29-
**Good luck and enjoy your coding!**
67+
Good luck.

modules/ode-1d/index.qmd

Lines changed: 60 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,94 @@
11
---
22
title: "Ordinary Differential Equations in 1D"
3-
subtitle: "Numerical Integration with SciPy"
3+
subtitle: "Initial Value Problems and Nonlinear Rate Laws"
44
format: html
55
---
66

7-
Numerical integration is fundamental for solving ordinary differential equations (ODEs) that don't have analytical solutions [@strogatz2024nonlinear; @virtanen2020scipy]. In this first session, you will learn how to:
7+
This first session builds the numerical workflow used throughout the whole course: define a right-hand side, choose an initial condition, integrate forward in time, and interpret the solution [@strogatz2024nonlinear; @virtanen2020scipy].
88

9-
- Formulate ODEs in Python.
10-
- Use SciPy's `solve_ivp` to numerically integrate ODEs.
11-
- Visualize solutions and explore parameter spaces.
12-
- Apply these techniques to real-world models.
9+
## From One Variable to Small Systems
1310

11+
The core mathematical object is the initial value problem
1412

15-
## Contents
13+
$$
14+
\dot y = f(t, y),
15+
\qquad
16+
y(t_0) = y_0.
17+
$$ {#eq-ode-1d-index-1}
1618
17-
- [SIR Epidemic Model](sir.qmd)
18-
- [Michaelis–Menten Enzyme Kinetics](michaelis-menten.qmd)
19-
- [Spruce Budworm Population Model](spruce-budworm.qmd)
20-
- [Assignment](assignment.qmd)
19+
In a scalar problem, $y(t)$ is one number. In a small system, $y(t)$ becomes a vector. The numerical workflow stays the same.
2120
22-
## The Initial Value Problem
21+
That is why this session starts with the label “1D” but already includes the SIR model: the main skill is not the number of components, but how you turn a rate law into a computable trajectory.
2322
24-
An **initial value problem (IVP)** consists of:
23+
## Case Studies
2524
26-
$$\frac{dy}{dt} = f(t, y), \quad y(t_0) = y_0$$ {#eq-ode-1d-index-1}
25+
Start with a classical epidemic model and see how a coupled ODE system fits into the same `solve_ivp` pipeline.
2726
28-
Where:
29-
- $f(t, y)$ is the rate of change function
30-
- $y_0$ is the initial condition at time $t_0$
27+
[SIR Epidemic Model](sir.qmd){.btn .btn-primary}
3128
32-
## SciPy's `solve_ivp`
29+
Then study a saturating nonlinear rate law through a Michaelis–Menten inspired example.
3330
34-
The `scipy.integrate.solve_ivp` function is the standard tool for solving ODEs in Python. Try the following code:
31+
[Michaelis–Menten Kinetics](michaelis-menten.qmd){.btn .btn-primary}
3532
36-
```python
37-
import numpy as np
38-
from scipy.integrate import solve_ivp
33+
Finally, combine phase-line reasoning, numerical integration, and interactivity in the spruce budworm model.
3934
40-
def exponential_decay(t, y):
41-
return -0.5 * y
35+
[Spruce Budworm Model](spruce-budworm.qmd){.btn .btn-primary}
4236
43-
t_span = [0, 10]
44-
y0 = [2, 4, 8]
45-
sol = solve_ivp(
46-
fun=exponential_decay,
47-
t_span=t_span,
48-
y0=y0)
37+
When the workflow is clear, move to the assignment.
4938
50-
print(sol.t)
39+
[Assignment](assignment.qmd){.btn .btn-secondary}
5140
52-
print(sol.y)
53-
```
41+
## Learning Goals
5442
55-
**How does `solve_ivp` work?** Let's understand its parameters (copied from the [documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html)):
43+
- Formulate an ODE or a small ODE system in Python.
44+
- Use `scipy.integrate.solve_ivp()` to integrate an initial value problem.
45+
- Interpret trajectories in time and connect them to parameters.
46+
- Recognize threshold, saturation, and bistability effects in simple models.
47+
- Reuse the same solver workflow across very different applications.
5648
57-
- `fun`: Right-hand side of the system: the time derivative of the state $y$ at time $t$. The calling signature is `fun(t, y)`, where `t` is a scalar and `y` is an ndarray with `len(y) = len(y0)`. Additional arguments need to be passed if `args` is used (see documentation of `args` argument). `fun` must return an array of the same shape as `y`.
58-
In our example, `exponential_decay` defines the ODE $\frac{dy}{dt} = -0.5y$, which models exponential decay $y(t) = y_0 e^{-0.5t}$.
59-
- `t_span`: Interval of integration $(t_0, t_f)$. The solver starts with $t=t_0$ and integrates until it reaches $t=t_f$. Both $t_0$ and $t_f$ must be floats or values interpretable by the float conversion function.
60-
- `y0`: Initial state. For problems in the complex domain, pass `y0` with a complex data type (even if the initial value is purely real).
49+
## Flow of This Session
6150
62-
You can also specify additional parameters:
63-
- `method`: Integration method to use. Common choices include `'RK45'` (default), `'RK23'`, `'DOP853'`, `'Radau'`, `'BDF'`, and `'LSODA'`.
64-
- `t_eval`: Times at which to store the computed solution, must be sorted and lie within `t_span`. If None (default), use points selected by the solver.
65-
- `args`: Additional arguments to pass to the user-defined functions. If, for example, `fun` has the signature `fun(t, y, a, b, c)`, then `args=(a, b, c)`.
51+
- Write the right-hand side of the model.
52+
- Choose parameters, a time span, and an initial condition.
53+
- Integrate with `solve_ivp()`.
54+
- Plot the solution and interpret the result.
55+
- Compare how the behavior changes when you vary parameters or initial data.
6656
67-
## Systems of ODEs
57+
## What do we need?
6858
69-
For multiple coupled equations, return a list or array of derivatives:
59+
### `scipy.integrate.solve_ivp`
60+
61+
This is the main solver for initial value problems in the course. It takes the right-hand side `fun(t, y)`, the interval `t_span`, the initial state `y0`, and optional arguments such as `t_eval`, `method`, and `args`.
7062
7163
```python
72-
def sir_model(t, y, beta, gamma):
73-
S, I, R = y
74-
N = S + I + R
75-
76-
dSdt = -beta * S * I / N
77-
dIdt = beta * S * I / N - gamma * I
78-
dRdt = gamma * I
79-
80-
return [dSdt, dIdt, dRdt]
64+
import numpy as np
65+
from scipy.integrate import solve_ivp
66+
67+
68+
def exponential_decay(t, y):
69+
return -0.5 * y
70+
71+
72+
sol = solve_ivp(
73+
exponential_decay,
74+
t_span=(0, 10),
75+
y0=[2.0],
76+
t_eval=np.linspace(0, 10, 200),
77+
)
8178
```
8279
83-
## Best Practices
80+
### `numpy`
81+
82+
Use NumPy arrays for initial conditions, evaluation grids, and post-processing of trajectories.
8483
85-
1. **Always check convergence**: Plot solutions at different tolerances
86-
2. **Use appropriate methods**: `'RK45'` (default) works well for most problems
87-
3. **Vectorize when possible**: Makes code faster and cleaner
88-
4. **Document parameters**: Keep track of units and meanings
89-
5. **Validate against known solutions**: Test your implementation
84+
### `matplotlib.pyplot`
9085
91-
## Next Steps
86+
Use Matplotlib to visualize time series, parameter comparisons, and phase-line style diagnostics.
9287
93-
Apply these techniques to the classical models in Session 1:
94-
- SIR epidemiological model
95-
- Spruce budworm population dynamics
96-
- Michaelis–Menten enzyme kinetics
88+
### Why start with `solve_ivp()`?
9789
98-
## Resources
90+
Because once you understand the initial value problem pipeline, you can reuse it almost unchanged in later sessions on planar systems, coupled oscillators, and PDE-inspired reductions.
9991
100-
- [SciPy solve_ivp documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html)
101-
- [Python for ODEs tutorial](https://python-numerical-methods.berkeley.edu/notebooks/chapter22.00-ODE-Initial-Value-Problems.html)
92+
::: {.callout-tip}
93+
The default `RK45` method is a good first choice for most examples in this session. Later sessions will make the method choice itself part of the modeling discussion.
94+
:::

modules/ode-1d/michaelis-menten.qmd

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
11
---
22
title: "Michaelis–Menten Enzyme Kinetics"
3-
subtitle: "1D Ordinary Differential Equations"
3+
subtitle: "Saturation as a One-Dimensional Rate Law"
44
format: html
55
---
66

7-
Michaelis–Menten kinetics is a foundational model in biochemical reaction dynamics [@michaelis1913kinetik]. It relates substrate concentration to reaction rate using a saturating nonlinearity.
7+
Michaelis–Menten kinetics is one of the standard examples of a saturating nonlinear rate law [@michaelis1913kinetik]. The classical instantaneous rate is
88

9-
The (simplified) substrate dynamics implemented in the reference script is:
9+
$$
10+
v(s) = \frac{V_{\max} s}{K_m + s},
11+
$$
12+
13+
where $V_{\max}$ is the maximum rate and $K_m$ is the Michaelis constant.
14+
15+
In the reference script used in this course, the same saturating expression is reused as a simple teaching ODE,
1016

1117
$$
1218
\dot s = \frac{V_{\max}s}{K_m + s}
1319
$$ {#eq-ode-1d-michaelis-menten-1}
1420
15-
where $V_{\max}$ is the maximum rate and $K_m$ is the Michaelis constant.
21+
This is not a full enzyme-substrate mass-action model. It is a compact one-dimensional example that lets you study how saturation changes both the rate curve and the time evolution of the state variable.
22+
23+
## Small and Large Concentration Regimes
24+
25+
The rate law has two useful asymptotic regimes:
26+
27+
$$
28+
v(s) \approx \frac{V_{\max}}{K_m} s \quad \text{for } s \ll K_m,
29+
\qquad
30+
v(s) \approx V_{\max} \quad \text{for } s \gg K_m.
31+
$$
32+
33+
So the system is approximately linear at small $s$ and nearly constant-rate at large $s$.
34+
35+
## Implement the Saturating Rate Law
36+
37+
```python
38+
def michaelis_menten(t, s, vmax=1.0, km=0.5):
39+
dsdt = (vmax * s) / (km + s)
40+
return dsdt
41+
```
1642
1743
## Reference Implementation {#sec-reference}
1844
@@ -42,6 +68,12 @@ plt.show()
4268
plt.close()
4369
```
4470
71+
## Interpret the Parameters
72+
73+
- Increasing $V_{\max}$ raises the saturation plateau.
74+
- Increasing $K_m$ shifts the curve so larger values of $s$ are needed before the rate is close to saturation.
75+
- In the teaching ODE used here, larger $V_{\max}$ also makes the state variable evolve faster in time.
76+
4577
## Exploration {#sec-exploration}
4678
4779
1. Increase $V_{\max}$ and observe how the rate curve changes.
@@ -52,3 +84,10 @@ plt.close()
5284
```bash
5385
python amlab/odes_1d/michaelis_menten.py
5486
```
87+
88+
## What's Next?
89+
90+
The Michaelis–Menten example highlights saturation. The spruce budworm model adds phase-line reasoning, multiple equilibria, and bistability.
91+
92+
[Spruce Budworm Model](spruce-budworm.qmd){.btn .btn-primary}
93+
[Back to Session Index](index.qmd){.btn .btn-secondary}

0 commit comments

Comments
 (0)