added snakemake context paragraph
parent
648cf8d4bd
commit
7dc42cb1cc
|
|
@ -1,2 +1,3 @@
|
||||||
venv
|
venv
|
||||||
Snakefile
|
Snakefile
|
||||||
|
/.snakemake/
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,24 @@ numerical integration scheme and the number of time steps.
|
||||||
The following function solves the ODE numerically:
|
The following function solves the ODE numerically:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
def solve_free_fall(eta, dt, total_time):
|
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.
|
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.
|
script file.
|
||||||
|
|
||||||
### Snakemake context
|
### 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"
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
Loading…
Reference in New Issue