added snakemake context paragraph

Lucas Frérot 2026-01-14 14:19:11 +01:00
parent 648cf8d4bd
commit 7dc42cb1cc
No known key found for this signature in database
GPG Key ID: 03B54A50E3FBA7E8
3 changed files with 114 additions and 1 deletions

1
.gitignore vendored

@ -1,2 +1,3 @@
venv
Snakefile
/.snakemake/

@ -13,8 +13,24 @@ numerical integration scheme and the number of time steps.
The following function solves the ODE numerically:
```python
import numpy as np
def solve_free_fall(eta, dt, total_time):
...
"""
Solve free fall equation with centered FD scheme.
Returns time and velocity values as Numpy arrays.
"""
Nsteps = int(total_time / dt)
v = np.zeros(Nsteps)
dv = 1
for i in range(Nsteps-1):
vpred = v[i] + dt / 2 * dv
dv = (1 - eta * vpred) / (1 + eta * dt / 2)
v[i+1] = vpred + dt / 2 * dv
return np.vstack((np.arange(Nsteps) * dt, v))
```
It returns a single array where the first line is time and the second line is velocity.
@ -77,3 +93,77 @@ happens. Let's see how to retrieve the wildcard values and output paths from the
script file.
### Snakemake context
A running script launched with Snakemake has access to the workflow context with
the `snakemake.script.snakemake` object, which we can import in our
`simulation.py` script:
```python
from snakemake.script import snakemake
```
You can print the following properties of the context object:
```python
print("input", snakemake.input)
print("output", snakemake.output)
print("wildcards", dict(snakemake.wildcards))
print("parameters", dict(snakemake.params))
```
We can test this with:
```
snakemake -j1 free_fall,eta=1,dt=1e-1,total_time=10.txt
< ... >
input
output free_fall,eta=1,dt=1e-1,total_time=10.txt
wildcards {'eta': '1', 'dt': '1e-1', 'total_time': '10'}
parameters {}
```
Note that the `snakemake.wildcards` object can be interpreted as a dictionary,
with each value associated to a wildcard being a string (note that the values
here are not numbers). This means numerical values need to be converted before
being passed on to our function.
Now that we know how to retrieve context values, we can use them to run our
simulation and save the result in a text file:
```python
wildcards = snakemake.wildcards
eta = float(wildcards.eta)
dt = float(wildcards.dt)
total_time = float(wildcards.total_time)
results = solve_free_fall(eta, dt, total_time)
np.savetxt(snakemake.output[0], results)
```
Note that `snakemake.output` is always a list. Since we only have one output, we
take `snakemake.output[0]`.
## New rule: plotting
We now want to implement the second part of the workflow: plotting the results
of a single simulation.
The rule we will implement will have an input file, which is the same as the
output of the previous rule. Snakemake makes this easy with a `rules` object
which is used to access context from other rules (such as output files). One
must be careful: **wildcards** need to be conserved between rules. The number of
wildcards in the output of a rule can never be smaller than the number of
wildcards in the input (although it can be larger). This means we have to reuse
the wildcards in the filename for the plot.
```python
rule simulation_plot:
input:
data=rules.simulation.output[0],
output:
plot_file='time_series,eta={eta},dt={dt},total_time={total_time}.pdf'
script:
"simulation_plot.py"
```

22
simulation.py Normal file

@ -0,0 +1,22 @@
import numpy as np
from snakemake.script import snakemake
def solve_free_fall(eta, dt, total_time):
Nsteps = int(total_time / dt)
v = np.zeros(Nsteps)
dv = 1
for i in range(Nsteps-1):
vpred = v[i] + dt / 2 * dv
dv = (1 - eta * vpred) / (1 + eta * dt / 2)
v[i+1] = vpred + dt / 2 * dv
return np.vstack((np.arange(Nsteps) * dt, v))
wildcards = snakemake.wildcards
eta = float(wildcards.eta)
dt = float(wildcards.dt)
total_time = float(wildcards.total_time)
results = solve_free_fall(eta, dt, total_time)
np.savetxt(snakemake.output[0], results)