I am building an example Workflow in snakemake, the Game of Life. In this particular example, I am using a starting grid that leads to an empty world after a few iterations. I would like to build a conditional workflow that checks for emptiness after each time step and stops the calculation of new time steps once the world is empty. It should then proceed to render a video from the displays of previous time steps.
To check for emptiness, I am using an input function and a checkpoint. Here is the Snakefile:
configfile: "config_exercise_2.yaml"
workdir: "../"
import numpy as np
Time = 1
def gridEmpty():
global Time
with open(checkpoints.CalculateNextTimeStep.get(time=Time).output[0],"rb") as f:
if np.all(np.load(f) == 0): #grid is empty, no more timesteps required
return [f"pictures/picture_t-{i}.jpg" for i in range(0,Time+1,1)]
else: #grid is not empty, more timesteps required
Time += 1
checkpoints.CalculateNextTimeStep.get(time=Time)
rule RenderVideo:
input:
gridEmpty
output:
"video/clip.mp4"
params:
framerate = config["FrameRate"]
shell:
"cat {input} | ffmpeg -framerate {params.framerate} -f image2pipe -i - {output}"
rule Displaytimestep:
input:
"arrays/array_t-{time}.npy"
output:
"pictures/picture_t-{time}.jpg"
conda:
"../environment/environment.yaml"
params:
timeStep = lambda wildcards: wildcards.time
script:
"../scripts/DisplayTimeStep.py"
checkpoint CalculateNextTimeStep:
input:
lambda wildcards: f"arrays/array_t-{int(wildcards.time)-1}.npy"
output:
"arrays/array_t-{time}.npy"
params:
GridSize = config["GridSize"]
conda:
"../environment/environment.yaml"
script:
"../scripts/CalculateNextTimeStep.py"
I remember that this code worked previously, however now I am getting
Error: TypeError: gridEmpty() takes 0 positional arguments but 1 was given Wildcards:
Traceback:
Which puzzles me, since I do not see where any arguments are given to the input function. Any ideas? Thank you!
When you use a function as input, like:
rule RenderVideo:
input:
gridEmpty
snakemake automatically calls the function using the wildcards
object as argument to the function. That is, it calls gridEmpty(wildcards)
. Since your definition of gridEmpty
does not take any parameter, you get the error you see.
The easiest solution may be to define gridEmpty
so that it takes one argument even if that argument is not used. Alternatively, this should also work and it is equivalent:
rule RenderVideo:
input:
lambda wildcards: gridEmpty(),
(NB: I haven't checked whether the rest of your code is correct)