Content from Ausführen von Befehlen mit Snakemake


Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten

Übersicht

Fragen

  • “Wie führe ich einen einfachen Befehl mit Snakemake aus?”

Ziele

  • “Erstelle ein Snakemake-Rezept (eine Snake-Datei)”

Für welchen Arbeitsablauf interessiere ich mich?


In dieser Lektion werden wir ein Experiment durchführen, bei dem wir eine parallel laufende Anwendung auf ihre Skalierbarkeit hin untersuchen. Dazu müssen wir Daten sammeln. In diesem Fall bedeutet das, dass wir die Anwendung mehrmals mit einer unterschiedlichen Anzahl von CPU-Kernen ausführen und die Ausführungszeit aufzeichnen. Danach müssen wir eine Visualisierung der Daten erstellen, um zu sehen, wie sie sich im Vergleich zum Idealfall verhalten.

Anhand der Visualisierung können wir dann entscheiden, in welchem Maßstab es am sinnvollsten ist, die Anwendung in der Produktion laufen zu lassen, um die CPU-Zuweisung auf dem System optimal zu nutzen.

Wir könnten all dies manuell tun, aber es gibt nützliche Tools, die uns bei der Verwaltung von Datenanalyse-Pipelines, wie wir sie in unserem Experiment haben, helfen. Heute werden wir eines dieser Tools kennenlernen: Snakemake.

Um mit Snakemake zu beginnen, nehmen wir zunächst einen einfachen Befehl und sehen, wie wir ihn mit Snakemake ausführen können. Wählen wir den Befehl hostname, der den Namen des Rechners ausgibt, auf dem der Befehl ausgeführt wird:

BASH

[ocaisa@node1 ~]$ hostname

AUSGABE

node1.int.jetstream2.hpc-carpentry.org

Das gibt das Ergebnis aus, aber Snakemake verlässt sich auf Dateien, um den Status Ihres Workflows zu kennen, also leiten wir die Ausgabe in eine Datei um:

BASH

[ocaisa@node1 ~]$ hostname > hostname_login.txt

Erstellen einer Snake-Datei


Bearbeiten Sie eine neue Textdatei mit dem Namen Snakefile.

Inhalt von Snakefile:

PYTHON

rule hostname_login:
    output: "hostname_login.txt"
    input:  
    shell:
        "hostname > hostname_login.txt"

Wichtige Punkte zu dieser Datei

  1. Die Datei heißt Snakefile - mit einem großen S und ohne Dateierweiterung.
  2. Einige Zeilen sind eingerückt. Einrückungen müssen mit Leerzeichen, nicht mit Tabulatoren erfolgen. Wie Sie Ihren Texteditor dazu bringen, dies zu tun, erfahren Sie im Abschnitt “Setup”.
  3. Die Regeldefinition beginnt mit dem Schlüsselwort rule, gefolgt von dem Namen der Regel und einem Doppelpunkt.
  4. Wir haben die Regel hostname_login genannt. Sie können Buchstaben, Zahlen oder Unterstriche verwenden, aber der Name der Regel muss mit einem Buchstaben beginnen und darf kein Schlüsselwort sein.
  5. Die Schlüsselwörter input, output und shell werden alle von einem Doppelpunkt (“:”) gefolgt.
  6. Die Dateinamen und der Shell-Befehl sind alle in "quotes".
  7. Der Name der Ausgabedatei wird vor dem Namen der Eingabedatei angegeben. Eigentlich ist es Snakemake egal, in welcher Reihenfolge sie erscheinen, aber wir geben in diesem Kurs die Ausgabe zuerst an. Wir werden gleich sehen, warum.
  8. In diesem Anwendungsfall gibt es keine Eingabedatei für den Befehl, also lassen wir dieses Feld leer.

Zurück in der Shell werden wir unsere neue Regel ausführen. An diesem Punkt, wenn es irgendwelche fehlenden Anführungszeichen, falsche Einrückungen, etc. gab, werden wir einen Fehler sehen.

BASH

snakemake -j1 -p hostname_login

bash: snakemake: command not found...

Wenn Ihre Shell Ihnen mitteilt, dass sie den Befehl snakemake nicht finden kann, müssen wir die Software irgendwie verfügbar machen. In unserem Fall bedeutet das, dass wir nach dem Modul suchen müssen, das wir laden wollen:

BASH

module spider snakemake

AUSGABE

[ocaisa@node1 ~]$ module spider snakemake

--------------------------------------------------------------------------------------------------------
  snakemake:
--------------------------------------------------------------------------------------------------------
     Versions:
        snakemake/8.2.1-foss-2023a
        snakemake/8.2.1 (E)

Names marked by a trailing (E) are extensions provided by another module.


--------------------------------------------------------------------------------------------------------
  For detailed information about a specific "snakemake" package (including how to load the modules) use the module's full name.
  Note that names that have a trailing (E) are extensions provided by other modules.
  For example:

     $ module spider snakemake/8.2.1
--------------------------------------------------------------------------------------------------------

Jetzt wollen wir das Modul, also laden wir es, um das Paket verfügbar zu machen

BASH

[ocaisa@node1 ~]$ module load snakemake

und dann stellen Sie sicher, dass der Befehl snakemake verfügbar ist

BASH

[ocaisa@node1 ~]$ which snakemake

AUSGABE

/cvmfs/software.eessi.io/host_injections/2023.06/software/linux/x86_64/amd/zen3/software/snakemake/8.2.1-foss-2023a/bin/snakemake

BASH

snakemake -j1 -p hostname_login

Ausführen von Snakemake

Führen Sie snakemake --help | less aus, um die Hilfe für alle verfügbaren Optionen zu sehen. Was bewirkt die Option -p in dem obigen Befehl snakemake?

  1. Schützt bestehende Ausgabedateien
  2. Gibt die Shell-Befehle, die gerade ausgeführt werden, auf dem Terminal aus
  3. Sagt Snakemake, dass es nur einen Prozess auf einmal ausführen soll
  4. Fordert den Benutzer auf, die richtige Eingabedatei zu wählen

Sie können im Text suchen, indem Sie / drücken, und mit q zur Shell zurückkehren.

  1. Gibt die Shell-Befehle, die gerade ausgeführt werden, auf dem Terminal aus

Dies ist so nützlich, dass wir nicht wissen, warum es nicht die Standardeinstellung ist! Die Option -j1 sagt Snakemake, dass es immer nur einen Prozess auf einmal ausführen soll, und wir bleiben vorerst dabei, da es die Dinge einfacher macht. Antwort 4 ist ein totales Ablenkungsmanöver, da Snakemake niemals interaktiv nach Benutzereingaben fragt.

Hauptpunkte

  • “Bevor Sie Snakemake starten, müssen Sie ein Snakefile schreiben”
  • “Ein Snakefile ist eine Textdatei, die eine Liste von Regeln definiert”
  • “Regeln haben Eingänge, Ausgänge und Shell-Befehle, die ausgeführt werden sollen”
  • “Du sagst Snakemake, welche Datei es erstellen soll, und es wird den in der entsprechenden Regel definierten Shell-Befehl ausführen”

Content from Ausführen von Snakemake auf dem Cluster


Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten

Übersicht

Fragen

  • “Wie führe ich meine Snakemake-Regel auf dem Cluster aus?”

Ziele

  • “Definieren Sie Regeln, die lokal und auf dem Cluster ausgeführt werden”

Was passiert, wenn wir unsere Regel auf dem Cluster und nicht auf dem Anmeldeknoten laufen lassen wollen? Der Cluster, den wir verwenden, benutzt Slurm, und es ist so, dass Snakemake eine eingebaute Unterstützung für Slurm hat, wir müssen ihm nur sagen, dass wir es benutzen wollen.

Snakemake verwendet die Option executor, um Ihnen die Möglichkeit zu geben, das Plugin auszuwählen, mit dem Sie die Regel ausführen möchten. Der schnellste Weg, dies auf Ihr Snakefile anzuwenden, ist, dies auf der Kommandozeile zu definieren. Probieren wir es aus

BASH

[ocaisa@node1 ~]$ snakemake -j1 -p --executor slurm hostname_login

AUSGABE

Building DAG of jobs...
Retrieving input from storage.
Nothing to be done (all requested files are present and up to date).

Nichts passiert! Warum nicht? Wenn Snakemake aufgefordert wird, ein Ziel zu erstellen, prüft es die “letzte Änderungszeit” sowohl des Ziels als auch seiner Abhängigkeiten. Wenn eine der Abhängigkeiten seit dem Ziel aktualisiert wurde, werden die Aktionen erneut ausgeführt, um das Ziel zu aktualisieren. Auf diese Weise weiß Snakemake, dass es nur die Dateien neu erstellen muss, die entweder direkt oder indirekt von der geänderten Datei abhängen. Dies wird inkrementeller Build genannt.

Inkrementelle Builds verbessern die Effizienz

Indem Snakemake Dateien nur bei Bedarf neu erstellt, macht es Ihre Verarbeitung effizienter.

Läuft auf dem Cluster

Wir brauchen jetzt eine weitere Regel, die die hostname auf dem Cluster ausführt. Erstellen Sie eine neue Regel in Ihrem Snakefile und versuchen Sie, sie auf dem Cluster mit der Option --executor slurm bis snakemake auszuführen.

Die Regel ist fast identisch mit der vorherigen Regel, abgesehen vom Namen der Regel und der Ausgabedatei:

PYTHON

rule hostname_remote:
    output: "hostname_remote.txt"
    input:
    shell:
        "hostname > hostname_remote.txt"

Sie können die Regel dann ausführen mit

BASH

[ocaisa@node1 ~]$ snakemake -j1 -p --executor slurm hostname_remote

AUSGABE

Building DAG of jobs...
Retrieving input from storage.
Using shell: /cvmfs/software.eessi.io/versions/2023.06/compat/linux/x86_64/bin/bash
Provided remote nodes: 1
Job stats:
job                count
---------------  -------
hostname_remote        1
total                  1

Select jobs to execute...
Execute 1 jobs...

[Mon Jan 29 18:03:46 2024]
rule hostname_remote:
    output: hostname_remote.txt
    jobid: 0
    reason: Missing output files: hostname_remote.txt
    resources: tmpdir=<TBD>

hostname > hostname_remote.txt
No SLURM account given, trying to guess.
Guessed SLURM account: def-users
No wall time information given. This might or might not work on your cluster.
If not, specify the resource runtime in your rule or as a reasonable default
via --default-resources. No job memory information ('mem_mb' or
'mem_mb_per_cpu') is given - submitting without.
This might or might not work on your cluster.
Job 0 has been submitted with SLURM jobid 326 (log: /home/ocaisa/.snakemake/slurm_logs/rule_hostname_remote/326.log).
[Mon Jan 29 18:04:26 2024]
Finished job 0.
1 of 1 steps (100%) done
Complete log: .snakemake/log/2024-01-29T180346.788174.snakemake.log

Beachten Sie die Warnungen, die Snakemake ausgibt, dass die Regel möglicherweise nicht auf unserem Cluster ausgeführt werden kann, da wir nicht genügend Informationen angegeben haben. Zum Glück für uns funktioniert dies auf unserem Cluster und wir können einen Blick in die Ausgabedatei werfen, die die neue Regel erzeugt, hostname_remote.txt:

BASH

[ocaisa@node1 ~]$ cat hostname_remote.txt

AUSGABE

tmpnode1.int.jetstream2.hpc-carpentry.org

Snakemake-Profil


Das Anpassen von Snakemake an eine bestimmte Umgebung kann viele Flags und Optionen mit sich bringen. Daher ist es möglich, ein Konfigurationsprofil anzugeben, das verwendet wird, um Standardoptionen zu erhalten. Das sieht dann so aus

BASH

snakemake --profile myprofileFolder ...

Der Profilordner muss eine Datei namens config.yaml enthalten, in der unsere Optionen gespeichert werden. Der Ordner kann auch andere Dateien enthalten, die für das Profil erforderlich sind. Erstellen wir die Datei cluster_profile/config.yaml und fügen wir einige unserer bestehenden Optionen ein:

YAML

printshellcmds: True
jobs: 3
executor: slurm

Wir sollten nun in der Lage sein, unseren Workflow erneut auszuführen, indem wir auf das Profil verweisen, anstatt die Optionen aufzulisten. Um die erneute Ausführung unseres Arbeitsablaufs zu erzwingen, müssen wir zuerst die Ausgabedatei hostname_remote.txt entfernen, und dann können wir unser neues Profil ausprobieren

BASH

[ocaisa@node1 ~]$ rm hostname_remote.txt
[ocaisa@node1 ~]$ snakemake --profile cluster_profile hostname_remote

Das Profil ist im Kontext unseres Clusters sehr nützlich, da der Slurm-Executor viele Optionen hat, die man manchmal benutzen muss, um Jobs an den Cluster zu übermitteln, auf den man Zugriff hat. Leider sind die Namen der Optionen in Snakemake nicht exakt dieselben wie die von Slurm, so dass wir die Hilfe einer Übersetzungstabelle benötigen:

SLURM Snakemake Description
--partition slurm_partition the partition a rule/job is to use
--time runtime the walltime per job in minutes
--constraint constraint may hold features on some clusters
--mem mem, mem_mb memory a cluster node must
provide (mem: string with unit), mem_mb: int
--mem-per-cpu mem_mb_per_cpu memory per reserved CPU
--ntasks tasks number of concurrent tasks / ranks
--cpus-per-task cpus_per_task number of cpus per task (in case of SMP, rather use threads)
--nodes nodes number of nodes

Die von Snakemake ausgegebenen Warnungen wiesen darauf hin, dass wir diese Optionen möglicherweise bereitstellen müssen. Eine Möglichkeit, dies zu tun, ist, sie als Teil der Snakemake-Regel mit dem Schlüsselwort resources anzugeben, z.B,

PYTHON

rule:
    input: ...
    output: ...
    resources:
        partition = <partition name>
        runtime = <some number>

und wir können das Profil auch verwenden, um Standardwerte für diese Optionen zu definieren, die wir für unser Projekt verwenden, indem wir das Schlüsselwort default-resources verwenden. Der verfügbare Arbeitsspeicher unseres Clusters beträgt beispielsweise etwa 4 GB pro Kern, so dass wir dies zu unserem Profil hinzufügen können:

YAML

printshellcmds: True
jobs: 3
executor: slurm
default-resources:
  - mem_mb_per_cpu=3600

Aufgabe

Wir wissen, dass unser Problem in einer sehr kurzen Zeit abläuft. Ändern Sie die Standardlänge unserer Jobs auf zwei Minuten für Slurm.

YAML

printshellcmds: True
jobs: 3
executor: slurm
default-resources:
  - mem_mb_per_cpu=3600
  - runtime=2

Es gibt verschiedene sbatch Optionen, die nicht direkt von den Ressourcendefinitionen in der obigen Tabelle unterstützt werden. Du kannst die slurm_extra Ressource benutzen, um jede dieser zusätzlichen Flags für sbatch anzugeben:

PYTHON

rule myrule:
    input: ...
    output: ...
    resources:
        slurm_extra="--mail-type=ALL --mail-user=<your email>"

Lokale Regelausführung


Unsere ursprüngliche Regel war es, den Hostnamen des Anmeldeknotens zu ermitteln. Wir wollen diese Regel immer auf dem Login-Knoten ausführen, damit sie Sinn macht. Wenn wir Snakemake anweisen, alle Regeln über den Slurm-Executor auszuführen (was wir über unser neues Profil tun), wird dies nicht mehr geschehen. Wie können wir also erzwingen, dass die Regel auf dem Anmeldeknoten ausgeführt wird?

Nun, in dem Fall, in dem eine Snakemake-Regel eine triviale Aufgabe ausführt, könnte die Übermittlung eines Jobs ein Overkill sein (z.B. weniger als 1 Minute Rechenzeit). Ähnlich wie in unserem Fall wäre es eine bessere Idee, diese Regeln lokal auszuführen (d.h. dort, wo der Befehl snakemake ausgeführt wird), anstatt sie als Job zu übermitteln. In Snakemake können Sie mit dem Schlüsselwort localrules angeben, welche Regeln immer lokal ausgeführt werden sollen. Definieren wir hostname_login als lokale Regel nahe dem Anfang unseres Snakefile.

PYTHON

localrules: hostname_login

Hauptpunkte

  • “Snakemake generiert und übermittelt seine eigenen Batch-Skripte für Ihren Scheduler.”
  • “Sie können Standardkonfigurationseinstellungen in einem Snakemake-Profil speichern”
  • localrules definiert Regeln, die lokal ausgeführt werden und nie an einen Cluster übermittelt werden.”

Content from Platzhalter


Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten

Übersicht

Fragen

  • “Wie kann ich eine generische Regel erstellen?”

Ziele

  • “Sehen Sie, wie Snakemake mit einigen Fehlern umgeht”

Unser Snakefile hat einige Duplikate. Zum Beispiel werden die Namen von Textdateien an einigen Stellen in den Snakefile-Regeln wiederholt. Snakefiles sind eine Form von Code, und in jedem Code können Wiederholungen zu Problemen führen (z. B. wenn wir eine Datendatei in einem Teil des Snakefiles umbenennen, aber vergessen, sie an anderer Stelle umzubenennen).

D.R.Y. (Don’t Repeat Yourself)

In vielen Programmiersprachen ist der Großteil der Sprachfunktionen dazu da, dem Programmierer die Möglichkeit zu geben, langatmige Berechnungsroutinen als kurzen, ausdrucksstarken und schönen Code zu beschreiben. Funktionen in Python, R oder Java, wie z. B. benutzerdefinierte Variablen und Funktionen, sind zum Teil deshalb nützlich, weil sie bedeuten, dass wir nicht alle Details immer und immer wieder ausschreiben (oder darüber nachdenken) müssen. Diese gute Angewohnheit, Dinge nur einmal auszuschreiben, ist bekannt als das “Don’t Repeat Yourself”-Prinzip oder D.R.Y.

Machen wir uns daran, einige der Wiederholungen aus unserem Snakefile zu entfernen.

Platzhalter


Um eine allgemeinere Regel zu erstellen, brauchen wir Platzhalter. Schauen wir uns mal an, wie ein Platzhalter aussieht

PYTHON

rule hostname_remote:
    output: "hostname_remote.txt"
    input:
    shell:
        "hostname > {output}"

Zur Erinnerung, hier ist die vorherige Version aus der letzten Folge:

PYTHON

rule hostname_remote:
    output: "hostname_remote.txt"
    input:
    shell:
        "hostname > hostname_remote.txt"

Die neue Regel hat explizite Dateinamen durch Dinge in {curly brackets} ersetzt, speziell {output} (aber es hätte auch {input} sein können…wenn das einen Wert hätte und nützlich wäre).

{input} und {output} sind Platzhalter

Platzhalter werden im Abschnitt shell einer Regel verwendet, und Snakemake ersetzt sie durch entsprechende Werte - {input} durch den vollständigen Namen der Eingabedatei und {output} durch den vollständigen Namen der Ausgabedatei – bevor der Befehl ausgeführt wird.

{resources} ist auch ein Platzhalter, und wir können auf ein benanntes Element des {resources} mit der Notation {resources.runtime} zugreifen (zum Beispiel).

Hauptpunkte

  • “Snakemake-Regeln werden mit Platzhaltern generischer gestaltet”
  • “Platzhalter im Shell-Teil der Regel werden durch Werte ersetzt, die auf den gewählten Platzhaltern basieren”

Content from MPI-Anwendungen und Snakemake


Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten

Übersicht

Fragen

  • “Wie kann ich eine MPI-Anwendung über Snakemake auf dem Cluster laufen lassen?”

Ziele

  • “Definieren Sie Regeln, die lokal und im Cluster ausgeführt werden sollen”

Jetzt ist es an der Zeit, sich wieder unserem eigentlichen Arbeitsablauf zuzuwenden. Wir können einen Befehl auf dem Cluster ausführen, aber was ist mit der Ausführung der MPI-Anwendung, an der wir interessiert sind? Unsere Anwendung heißt amdahl und ist als Umgebungsmodul verfügbar.

Aufgabe

Suchen und laden Sie das Modul amdahl und ersetzen Sie dann unsere hostname_remote-Regel durch eine Version, die amdahl ausführt. (Machen Sie sich noch keine Gedanken über paralleles MPI, lassen Sie es mit einer einzelnen CPU laufen, mpiexec -n 1 amdahl).

Wurde Ihre Regel korrekt ausgeführt? Wenn nicht, sehen Sie sich die Protokolldateien an, um herauszufinden, warum?

BASH

module spider amdahl
module load amdahl

findet und lädt das Modul amdahl. Wir können dann unsere Regel aktualisieren/ersetzen, um die Anwendung amdahl auszuführen:

PYTHON

rule amdahl_run:
    output: "amdahl_run.txt"
    input:
    shell:
        "mpiexec -n 1 amdahl > {output}"

Wenn wir jedoch versuchen, die Regel auszuführen, erhalten wir eine Fehlermeldung (es sei denn, Sie haben bereits eine andere Version von amdahl in Ihrem Pfad verfügbar). Snakemake meldet den Speicherort der Protokolle und wenn wir darin nachsehen, finden wir (eventuell)

AUSGABE

...
mpiexec -n 1 amdahl > amdahl_run.txt
--------------------------------------------------------------------------
mpiexec was unable to find the specified executable file, and therefore
did not launch the job.  This error was first reported for process
rank 0; it may have occurred for other processes as well.

NOTE: A common cause for this error is misspelling a mpiexec command
      line parameter option (remember that mpiexec interprets the first
      unrecognized command line token as the executable).

Node:       tmpnode1
Executable: amdahl
--------------------------------------------------------------------------
...

Obwohl wir das Modul vor der Ausführung des Workflows geladen haben, hat unsere Snakemake-Regel die ausführbare Datei nicht gefunden. Das liegt daran, dass die Snakemake-Regel in einer sauberen Laufzeitumgebung läuft, und wir müssen ihr irgendwie sagen, dass sie das notwendige Umgebungsmodul laden soll, bevor wir versuchen, die Regel auszuführen.

Snakemake und Umgebungsmodule


Unsere Anwendung heißt amdahl und ist auf dem System über ein Umgebungsmodul verfügbar, also müssen wir Snakemake sagen, dass es das Modul laden soll, bevor es versucht, die Regel auszuführen. Snakemake kennt Umgebungsmodule, und diese können über eine (weitere) Option angegeben werden:

PYTHON

rule amdahl_run:
    output: "amdahl_run.txt"
    input:
    envmodules:
      "mpi4py",
      "amdahl"
    input:
    shell:
        "mpiexec -n 1 amdahl > {output}"

Das Hinzufügen dieser Zeilen reicht jedoch nicht aus, damit die Regel ausgeführt wird. Sie müssen Snakemake nicht nur mitteilen, welche Module geladen werden sollen, sondern auch, dass es generell Umgebungsmodule verwenden soll (da die Verwendung von Umgebungsmodulen Ihre Laufzeitumgebung weniger reproduzierbar macht, da sich die verfügbaren Module von Cluster zu Cluster unterscheiden können). Dazu müssen Sie Snakemake eine zusätzliche Option geben

BASH

snakemake --profile cluster_profile --use-envmodules amdahl_run

Aufgabe

Wir werden im weiteren Verlauf des Tutorials Umgebungsmodule verwenden, also machen Sie diese Option zu einer Standardoption unseres Profils (indem Sie den Wert auf True setzen)

Aktualisieren Sie unser Clusterprofil auf

YAML

printshellcmds: True
jobs: 3
executor: slurm
default-resources:
  - mem_mb_per_cpu=3600
  - runtime=2
use-envmodules: True

Wenn Sie es testen wollen, müssen Sie die Ausgabedatei der Regel löschen und Snakemake erneut ausführen.

Snakemake und MPI


Im letzten Abschnitt haben wir nicht wirklich eine MPI-Anwendung laufen lassen, da wir nur auf einem Kern gearbeitet haben. Wie können wir für eine einzelne Regel die Ausführung auf mehreren Kernen anfordern?

Snakemake bietet allgemeine Unterstützung für MPI, aber der einzige Executor, der MPI derzeit explizit unterstützt, ist der Slurm-Executor (ein Glück für uns!). Wenn wir uns unsere Übersetzungstabelle von Slurm nach Snakemake ansehen, stellen wir fest, dass die relevanten Optionen am unteren Rand erscheinen:

SLURM Snakemake Description
--ntasks tasks number of concurrent tasks / ranks
--cpus-per-task cpus_per_task number of cpus per task (in case of SMP, rather use threads)
--nodes nodes number of nodes

Diejenige, die uns interessiert, ist tasks, da wir nur die Anzahl der Ränge erhöhen wollen. Wir können diese in einem resources-Abschnitt unserer Regel definieren und mit Platzhaltern auf sie verweisen:

PYTHON

rule amdahl_run:
    output: "amdahl_run.txt"
    input:
    envmodules:
      "amdahl"
    resources:
      mpi='mpiexec',
      tasks=2
    input:
    shell:
        "{resources.mpi} -n {resources.tasks} amdahl > {output}"

Das hat funktioniert, aber jetzt haben wir ein kleines Problem. Wir wollen dies für einige verschiedene Werte von tasks machen, was bedeuten würde, dass wir für jeden Lauf eine andere Ausgabedatei benötigen. Es wäre großartig, wenn wir irgendwie in output den Wert angeben könnten, den wir für tasks verwenden wollen… und Snakemake das übernehmen könnte.

Wir koennten eine Wildcard in output benutzen, um das tasks zu definieren, das wir benutzen wollen. Die Syntax für einen solchen Platzhalter sieht wie folgt aus

PYTHON

output: "amdahl_run_{parallel_tasks}.txt"

wobei parallel_tasks unser Platzhalter ist.

Wildcards

Wildcards werden in den Zeilen input und output der Regel verwendet, um Teile von Dateinamen zu repräsentieren. Ähnlich wie das Muster * in der Shell kann der Platzhalter für jeden beliebigen Text stehen, um den gewünschten Dateinamen zu bilden. Wie bei der Benennung Ihrer Regeln können Sie auch für Ihre Platzhalter einen beliebigen Namen wählen, hier also parallel_tasks. Durch die Verwendung der gleichen Platzhalter in der Eingabe und der Ausgabe wird Snakemake mitgeteilt, wie die Eingabedateien den Ausgabedateien zugeordnet werden sollen.

Wenn zwei Regeln einen Platzhalter mit demselben Namen verwenden, werden sie von Snakemake als unterschiedliche Entitäten behandelt - Regeln in Snakemake sind auf diese Weise in sich geschlossen.

In der Zeile shell kann man den Platzhalter mit {wildcards.parallel_tasks} referenzieren

Snakemake Reihenfolge der Operationen


Wir fangen gerade erst mit ein paar einfachen Regeln an, aber es lohnt sich, darüber nachzudenken, was Snakemake genau macht, wenn Sie es ausführen. Es gibt drei verschiedene Phasen:

  1. Bereitet sich auf die Ausführung vor:
    1. Liest alle Regeldefinitionen aus dem Snakefile ein
  2. Planen Sie, was zu tun ist:
    1. Zeigt an, welche Datei(en) Sie erstellen möchten
    2. Sucht nach einer passenden Regel, indem es die output aller ihm bekannten Regeln betrachtet
    3. Füllt die Platzhalter aus, um die input für diese Regel zu berechnen
    4. Prüft, ob diese Eingabedatei (falls erforderlich) tatsächlich vorhanden ist
  3. Führt die Schritte aus:
    1. Erzeugt das Verzeichnis für die Ausgabedatei, falls erforderlich
    2. Entfernt die alte Ausgabedatei, wenn sie bereits vorhanden ist
    3. Nur dann wird der Shell-Befehl mit den ersetzten Platzhaltern ausgeführt
    4. Prüft, ob der Befehl ohne Fehler gelaufen ist und die neue Ausgabedatei wie erwartet erstellt hat

Trockenlauf (-n) Modus

Es ist oft nützlich, nur die ersten beiden Phasen laufen zu lassen, so dass Snakemake die auszuführenden Jobs plant und sie auf den Bildschirm ausgibt, sie aber nie tatsächlich ausführt. Dies wird mit dem -n Flag erreicht, z.B.:

BASH

> $ snakemake -n ...

Die Anzahl der Überprüfungen mag im Moment noch pedantisch erscheinen, aber wenn der Arbeitsablauf mehr Schritte umfasst, wird dies in der Tat sehr nützlich für uns werden.

Verwendung von Wildcards in unserer Regel


Wir möchten einen Platzhalter in output verwenden, um die Anzahl der tasks zu definieren, die wir verwenden möchten. Ausgehend von dem, was wir bisher gesehen haben, könnten Sie sich vorstellen, dass dies wie folgt aussehen könnte

PYTHON

rule amdahl_run:
    output: "amdahl_run_{parallel_tasks}.txt"
    input:
    envmodules:
      "amdahl"
    resources:
      mpi="mpiexec",
      tasks="{parallel_tasks}"
    input:
    shell:
        "{resources.mpi} -n {resources.tasks} amdahl > {output}"

aber es gibt zwei Probleme damit:

  • Die einzige Möglichkeit für Snakemake, den Wert des Platzhalters zu erfahren, besteht darin, dass der Benutzer explizit eine konkrete Ausgabedatei anfordert (anstatt die Regel aufzurufen):

BASH

  snakemake --profile cluster_profile amdahl_run_2.txt

Dies ist absolut gültig, da Snakemake herausfinden kann, dass es eine Regel hat, die auf diesen Dateinamen passt.

  • Das größere Problem ist, dass selbst das nicht funktioniert, es scheint, dass wir keinen Platzhalter für tasks verwenden können:

    AUSGABE

    WorkflowError:
    SLURM job submission failed. The error message was sbatch:
    error: Invalid numeric value "{parallel_tasks}" for --ntasks.

Leider gibt es für uns keine direkte Möglichkeit, auf die Platzhalter für tasks zuzugreifen. Der Grund dafür ist, dass Snakemake versucht, den Wert von tasks während seiner Initialisierungsphase zu verwenden, also bevor wir den Wert des Platzhalters kennen. Wir müssen die Bestimmung von tasks auf einen späteren Zeitpunkt verschieben. Dies kann erreicht werden, indem für dieses Szenario eine Eingabefunktion anstelle eines Wertes angegeben wird. Die Lösung besteht also darin, eine einmalig zu verwendende Funktion zu schreiben, die Snakemake dazu bringt, dies für uns zu tun. Da die Funktion speziell für die Regel gedacht ist, können wir eine einzeilige Funktion ohne Namen verwenden. Diese Art von Funktionen werden entweder anonyme Funktionen oder Lamdba-Funktionen genannt (beide bedeuten dasselbe) und sind ein Merkmal von Python (und anderen Programmiersprachen).

Um eine Lambda-Funktion in Python zu definieren, ist die allgemeine Syntax wie folgt:

PYTHON

lambda x: x + 54

Da unsere Funktion die Platzhalter als Argumente benutzen kann, können wir damit den Wert für tasks setzen:

PYTHON

rule amdahl_run:
    output: "amdahl_run_{parallel_tasks}.txt"
    input:
    envmodules:
      "amdahl"
    resources:
      mpi="mpiexec",
      # No direct way to access the wildcard in tasks, so we need to do this
      # indirectly by declaring a short function that takes the wildcards as an
      # argument
      tasks=lambda wildcards: int(wildcards.parallel_tasks)
    input:
    shell:
        "{resources.mpi} -n {resources.tasks} amdahl > {output}"

Jetzt haben wir eine Regel, die verwendet werden kann, um die Ausgabe von Läufen einer beliebigen Anzahl von parallelen Aufgaben zu erzeugen.

Kommentare in Snakefiles

Im obigen Code ist die Zeile, die mit # beginnt, eine Kommentarzeile. Hoffentlich haben Sie sich bereits angewöhnt, Kommentare in Ihre eigenen Skripte einzufügen. Gute Kommentare machen jedes Skript besser lesbar, und das gilt auch für Snakefiles.

Da unsere Regel nun in der Lage ist, eine beliebige Anzahl von Ausgabedateien zu erzeugen, könnte es in unserem aktuellen Verzeichnis sehr voll werden. Es ist daher wahrscheinlich am besten, die Läufe in einen separaten Ordner zu legen, um Ordnung zu schaffen. Wir können den Ordner direkt zu unserem output hinzufügen und Snakemake wird die Erstellung des Verzeichnisses für uns übernehmen:

PYTHON

rule amdahl_run:
    output: "runs/amdahl_run_{parallel_tasks}.txt"
    input:
    envmodules:
      "amdahl"
    resources:
      mpi="mpiexec",
      # No direct way to access the wildcard in tasks, so we need to do this
      # indirectly by declaring a short function that takes the wildcards as an
      # argument
      tasks=lambda wildcards: int(wildcards.parallel_tasks)
    input:
    shell:
        "{resources.mpi} -n {resources.tasks} amdahl > {output}"

Aufgabe

Erzeugt eine Ausgabedatei (unter dem Ordner runs) für den Fall, dass wir 6 parallele Aufgaben haben

(TIPP: Denken Sie daran, dass Snakemake in der Lage sein muss, die angeforderte Datei mit dem output einer Regel abzugleichen)

BASH

snakemake --profile cluster_profile runs/amdahl_run_6.txt

Ein weiterer Punkt bei unserer Anwendung amdahl ist, dass wir letztendlich die Ausgabe verarbeiten wollen, um unsere Skalierungsdarstellung zu erzeugen. Die derzeitige Ausgabe ist zwar nützlich zum Lesen, erschwert aber die Verarbeitung. amdahl hat eine Option, die dies für uns einfacher macht. Um die amdahl Optionen zu sehen, können wir verwenden

BASH

[ocaisa@node1 ~]$ module load amdahl
[ocaisa@node1 ~]$ amdahl --help

AUSGABE

usage: amdahl [-h] [-p [PARALLEL_PROPORTION]] [-w [WORK_SECONDS]] [-t] [-e]

options:
  -h, --help            show this help message and exit
  -p [PARALLEL_PROPORTION], --parallel-proportion [PARALLEL_PROPORTION]
                        Parallel proportion should be a float between 0 and 1
  -w [WORK_SECONDS], --work-seconds [WORK_SECONDS]
                        Total seconds of workload, should be an integer greater than 0
  -t, --terse           Enable terse output
  -e, --exact           Disable random jitter

Die Option, nach der wir suchen, ist --terse, und die bewirkt, dass amdahl die Ausgabe in einem Format ausgibt, das viel einfacher zu verarbeiten ist, nämlich JSON. Das JSON-Format in einer Datei verwendet normalerweise die Dateierweiterung .json, also fügen wir diese Option zu unserem shell-Befehl hinzu und ändern das Dateiformat von output, damit es zu unserem neuen Befehl passt:

PYTHON

rule amdahl_run:
    output: "runs/amdahl_run_{parallel_tasks}.json"
    input:
    envmodules:
      "amdahl"
    resources:
      mpi="mpiexec",
      # No direct way to access the wildcard in tasks, so we need to do this
      # indirectly by declaring a short function that takes the wildcards as an
      # argument
      tasks=lambda wildcards: int(wildcards.parallel_tasks)
    input:
    shell:
        "{resources.mpi} -n {resources.tasks} amdahl --terse > {output}"

Es gab einen weiteren Parameter für amdahl, der mir aufgefallen ist. amdahl hat eine Option --parallel-proportion (oder -p), an deren Änderung wir interessiert sein könnten, da sie das Verhalten des Codes verändert und sich somit auf die Werte auswirkt, die wir in unseren Ergebnissen erhalten. Fügen wir eine weitere Verzeichnisebene zu unserem Ausgabeformat hinzu, um eine bestimmte Wahl für diesen Wert wiederzugeben. Wir können einen Platzhalter verwenden, damit wir den Wert gleich auswählen müssen:

PYTHON

rule amdahl_run:
    output: "p_{parallel_proportion}/runs/amdahl_run_{parallel_tasks}.json"
    input:
    envmodules:
      "amdahl"
    resources:
      mpi="mpiexec",
      # No direct way to access the wildcard in tasks, so we need to do this
      # indirectly by declaring a short function that takes the wildcards as an
      # argument
      tasks=lambda wildcards: int(wildcards.parallel_tasks)
    input:
    shell:
        "{resources.mpi} -n {resources.tasks} amdahl --terse -p {wildcards.parallel_proportion} > {output}"

Aufgabe

Erstellt eine Ausgabedatei für einen Wert von -p von 0,999 (der Standardwert ist 0,8) für den Fall, dass wir 6 parallele Aufgaben haben.

BASH

snakemake --profile cluster_profile p_0.999/runs/amdahl_run_6.json

Hauptpunkte

  • “Snakemake wählt die passende Regel durch Ersetzen von Platzhaltern, so dass die Ausgabe mit dem Ziel übereinstimmt”
  • “Snakemake prüft auf verschiedene Fehlerbedingungen und hält an, wenn es ein Problem sieht”

Content from Verkettung von Regeln


Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten

Übersicht

Fragen

  • “Wie kombiniere ich Regeln zu einem Workflow?”
  • “Wie erstelle ich eine Regel mit mehreren Eingaben und Ausgaben?”

Ziele

  • “”

Eine Pipeline mit mehreren Regeln


Wir haben jetzt eine Regel, die eine Ausgabe für jeden Wert von -p und eine beliebige Anzahl von Aufgaben erzeugen kann, wir müssen Snakemake nur mit den gewünschten Parametern aufrufen:

BASH

snakemake --profile cluster_profile p_0.999/runs/amdahl_run_6.json

Das ist allerdings nicht gerade praktisch, denn um einen vollständigen Datensatz zu erzeugen, müssen wir Snakemake viele Male mit verschiedenen Ausgabedateien ausführen. Lassen Sie uns stattdessen eine Regel erstellen, die diese Dateien für uns generieren kann.

Die Verkettung von Regeln in Snakemake ist eine Frage der Wahl von Dateinamensmustern, die die Regeln verbinden. Das ist eine Kunst für sich - meistens gibt es mehrere Möglichkeiten, die funktionieren:

PYTHON

rule generate_run_files:
    output: "p_{parallel_proportion}_runs.txt"
    input:  "p_{parallel_proportion}/runs/amdahl_run_6.json"
    shell:
        "echo {input} done > {output}"

Aufgabe

Die neue Regel macht keine Arbeit, sie stellt nur sicher, dass wir die gewünschte Datei erzeugen. Sie ist es nicht wert, auf dem Cluster ausgeführt zu werden. Wie kann man sicherstellen, dass sie nur auf dem Anmeldeknoten ausgeführt wird?

Wir müssen die neue Regel zu unserer localrules hinzufügen:

PYTHON

localrules: hostname_login, generate_run_files

Führen wir nun die neue Regel aus (denken Sie daran, dass wir die Ausgabedatei mit dem Namen anfordern müssen, da das output in unserer Regel ein Platzhaltermuster enthält):

BASH

[ocaisa@node1 ~]$ snakemake --profile cluster_profile/ p_0.999_runs.txt

AUSGABE

Using profile cluster_profile/ for setting default command line arguments.
Building DAG of jobs...
Retrieving input from storage.
Using shell: /cvmfs/software.eessi.io/versions/2023.06/compat/linux/x86_64/bin/bash
Provided remote nodes: 3
Job stats:
job                   count
------------------  -------
amdahl_run                1
generate_run_files        1
total                     2

Select jobs to execute...
Execute 1 jobs...

[Tue Jan 30 17:39:29 2024]
rule amdahl_run:
    output: p_0.999/runs/amdahl_run_6.json
    jobid: 1
    reason: Missing output files: p_0.999/runs/amdahl_run_6.json
    wildcards: parallel_proportion=0.999, parallel_tasks=6
    resources: mem_mb=1000, mem_mib=954, disk_mb=1000, disk_mib=954,
               tmpdir=<TBD>, mem_mb_per_cpu=3600, runtime=2, mpi=mpiexec, tasks=6

mpiexec -n 6 amdahl --terse -p 0.999 > p_0.999/runs/amdahl_run_6.json
No SLURM account given, trying to guess.
Guessed SLURM account: def-users
Job 1 has been submitted with SLURM jobid 342 (log: /home/ocaisa/.snakemake/slurm_logs/rule_amdahl_run/342.log).
[Tue Jan 30 17:47:31 2024]
Finished job 1.
1 of 2 steps (50%) done
Select jobs to execute...
Execute 1 jobs...

[Tue Jan 30 17:47:31 2024]
localrule generate_run_files:
    input: p_0.999/runs/amdahl_run_6.json
    output: p_0.999_runs.txt
    jobid: 0
    reason: Missing output files: p_0.999_runs.txt;
            Input files updated by another job: p_0.999/runs/amdahl_run_6.json
    wildcards: parallel_proportion=0.999
    resources: mem_mb=1000, mem_mib=954, disk_mb=1000, disk_mib=954,
               tmpdir=/tmp, mem_mb_per_cpu=3600, runtime=2

echo p_0.999/runs/amdahl_run_6.json done > p_0.999_runs.txt
[Tue Jan 30 17:47:31 2024]
Finished job 0.
2 of 2 steps (100%) done
Complete log: .snakemake/log/2024-01-30T173929.781106.snakemake.log

Schauen Sie sich die Logging-Meldungen an, die Snakemake im Terminal ausgibt. Was ist hier passiert?

  1. Snakemake sucht nach einer Regel, die p_0.999_runs.txt erzeugt
  2. Es bestimmt, dass “generate_run_files” dies machen kann, wenn parallel_proportion=0.999
  3. Es sieht, dass die benötigte Eingabe also p_0.999/runs/amdahl_run_6.json ist
  4. Snakemake sucht nach einer Regel, die p_0.999/runs/amdahl_run_6.json erzeugt
  5. Es wird festgestellt, dass “amdahl_run” dies machen kann, wenn parallel_proportion=0.999 und parallel_tasks=6
  6. Nachdem Snakemake eine verfügbare Eingabedatei erreicht hat (in diesem Fall ist eigentlich keine Eingabedatei erforderlich), führt es beide Schritte aus, um die endgültige Ausgabe zu erhalten

Dies ist, kurz gesagt, wie wir Arbeitsabläufe in Snakemake aufbauen.

  1. Definieren Sie Regeln für alle Verarbeitungsschritte
  2. Wählen Sie input und output Namensmuster, die es Snakemake erlauben, die Regeln zu verknüpfen
  3. Sagt Snakemake, dass es die endgültige(n) Ausgabedatei(en) erzeugen soll

Wenn Sie es gewohnt sind, reguläre Skripte zu schreiben, ist dies ein wenig gewöhnungsbedürftig. Anstatt die Schritte in der Reihenfolge ihrer Ausführung aufzulisten, arbeiten Sie immer rückwärts vom gewünschten Endergebnis aus. Die Reihenfolge der Operationen wird durch die Anwendung der Mustervergleichsregeln auf die Dateinamen bestimmt, nicht durch die Reihenfolge der Regeln in der Snakefile.

Outputs first?

Der Ansatz von Snakemake, von der gewünschten Ausgabe rückwärts zu arbeiten, um den Arbeitsablauf zu bestimmen, ist der Grund, warum wir die output-Zeilen an den Anfang all unserer Regeln setzen - um uns daran zu erinnern, dass es diese sind, die Snakemake zuerst betrachtet!

Viele Benutzer von Snakemake, und auch die offizielle Dokumentation, bevorzugen es, die input an erster Stelle zu haben, also sollten Sie in der Praxis die Reihenfolge verwenden, die für Sie sinnvoll ist.

log Ausgaben in Snakemake

Snakemake hat ein eigenes Regelfeld für Ausgaben, die [Logdateien] (https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#log-files) sind, und diese werden größtenteils wie reguläre Ausgaben behandelt, außer dass Logdateien nicht entfernt werden, wenn der Job einen Fehler produziert. Das bedeutet, dass Sie sich das Protokoll ansehen können, um den Fehler zu diagnostizieren. In einem echten Arbeitsablauf kann dies sehr nützlich sein, aber um die Grundlagen von Snakemake zu erlernen, bleiben wir hier bei den regulären input und output Feldern.

Fehler sind normal

Lassen Sie sich nicht entmutigen, wenn Sie beim ersten Testen Ihrer neuen Snakemake-Pipelines Fehler sehen. Beim Schreiben eines neuen Arbeitsablaufs kann eine Menge schief gehen, und Sie werden normalerweise mehrere Iterationen benötigen, um alles richtig zu machen. Ein Vorteil des Snakemake-Ansatzes im Vergleich zu normalen Skripten ist, dass Snakemake bei Problemen schnell abbricht, anstatt weiterzumachen und möglicherweise unbrauchbare Berechnungen mit unvollständigen oder beschädigten Daten durchzuführen. Ein weiterer Vorteil besteht darin, dass wir bei einem fehlgeschlagenen Schritt sicher dort weitermachen können, wo wir aufgehört haben.

Hauptpunkte

  • “Snakemake verknüpft Regeln, indem es iterativ nach Regeln sucht, die fehlende Eingaben machen”
  • “Regeln können mehrere benannte Eingänge und/oder Ausgänge haben”
  • “Wenn ein Shell-Befehl nicht die erwartete Ausgabe liefert, wird Snakemake dies als Fehler betrachten

Content from Verarbeitung von Listen von Eingaben


Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten

Übersicht

Fragen

  • “Wie kann ich mehrere Dateien auf einmal verarbeiten?”
  • “Wie kombiniere ich mehrere Dateien miteinander?”

Ziele

  • “Verwenden Sie Snakemake, um alle unsere Proben auf einmal zu verarbeiten”
  • “Erstellen Sie ein Skalierbarkeitsdiagramm, das unsere Ergebnisse zusammenfasst”

Wir haben eine Regel erstellt, die eine einzige Ausgabedatei erzeugen kann, aber wir werden nicht mehrere Regeln für jede Ausgabedatei erstellen. Wir wollen alle Ausführungsdateien mit einer einzigen Regel erzeugen, wenn es möglich ist, und Snakemake kann tatsächlich eine Liste von Eingabedateien annehmen:

PYTHON

rule generate_run_files:
    output: "p_{parallel_proportion}_runs.txt"
    input:  "p_{parallel_proportion}/runs/amdahl_run_2.json", "p_{parallel_proportion}/runs/amdahl_run_6.json"
    shell:
        "echo {input} done > {output}"

Das ist großartig, aber wir wollen nicht alle Dateien, an denen wir interessiert sind, einzeln auflisten müssen. Wie können wir dies tun?

Definieren einer Liste von zu verarbeitenden Proben


Um dies zu tun, können wir einige Listen als Snakemake globale Variablen definieren.

Globale Variablen sollten vor den Regeln in der Snakefile hinzugefügt werden.

PYTHON

# Task sizes we wish to run
NTASK_SIZES = [1, 2, 3, 4, 5]
  • Anders als bei Variablen in Shell-Skripten können wir Leerzeichen um das =-Zeichen setzen, aber sie sind nicht zwingend erforderlich.
  • Die Listen der in Anführungszeichen gesetzten Zeichenketten werden in eckige Klammern gesetzt und durch Kommata getrennt. Wenn Sie Python kennen, werden Sie dies als Python-Listensyntax erkennen.
  • Eine gute Konvention ist die Verwendung von großgeschriebenen Namen für diese Variablen, aber das ist nicht zwingend.
  • Obwohl diese als Variablen bezeichnet werden, können Sie die Werte nicht mehr ändern, sobald der Arbeitsablauf läuft, so dass auf diese Weise definierte Listen eher Konstanten sind.

Verwendung einer Snakemake-Regel zur Definition eines Stapels von Ausgaben


Nun wollen wir unser Snakefile aktualisieren, um die neue globale Variable zu nutzen und eine Liste von Dateien zu erstellen:

PYTHON

rule generate_run_files:
    output: "p_{parallel_proportion}_runs.txt"
    input:  expand("p_{{parallel_proportion}}/runs/amdahl_run_{count}.json", count=NTASK_SIZES)
    shell:
        "echo {input} done > {output}"

Die Funktion expand(...) in dieser Regel erzeugt eine Liste von Dateinamen, indem sie das erste Element in den einfachen Klammern als Vorlage nimmt und {count} durch alle NTASK_SIZES ersetzt. Da die Liste 5 Elemente enthält, ergibt dies 5 Dateien, die wir erstellen wollen. Beachten Sie, dass wir unseren Platzhalter in einem zweiten Satz von Klammern schützen mussten, damit er nicht als etwas interpretiert wird, das erweitert werden muss.

In unserem aktuellen Fall verlassen wir uns immer noch auf den Dateinamen, um den Wert des Platzhalters parallel_proportion zu definieren, also können wir die Regel nicht direkt aufrufen, sondern müssen immer noch eine bestimmte Datei anfordern:

BASH

snakemake --profile cluster_profile/ p_0.999_runs.txt

Wenn Sie beim Ausführen von Snakemake auf der Befehlszeile keinen Namen für eine Zielregel oder Dateinamen angeben, wird standardmäßig die erste Regel in der Snake-Datei als Ziel verwendet.

Regeln als Ziele

Wenn Sie Snakemake den Namen einer Regel auf der Kommandozeile geben, funktioniert das nur, wenn diese Regel keine Platzhalter in den Ausgaben hat, weil Snakemake keine Möglichkeit hat, zu wissen, was die gewünschten Platzhalter sein könnten. Sie erhalten die Fehlermeldung “Target rules may not contain wildcards” Dies kann auch passieren, wenn Sie in der Befehlszeile keine expliziten Ziele angeben und Snakemake versucht, die erste im Snakefile definierte Regel auszuführen.

Regeln, die mehrere Eingaben kombinieren


Unsere generate_run_files Regel ist eine Regel, die eine Liste von Eingabedateien annimmt. Die Länge dieser Liste ist nicht durch die Regel festgelegt, sondern kann sich je nach NTASK_SIZES ändern.

In unserem Arbeitsablauf besteht der letzte Schritt darin, alle generierten Dateien in einem Plot zu kombinieren. Vielleicht haben Sie schon gehört, dass einige Leute dafür eine Python-Bibliothek namens matplotlib verwenden. Es würde den Rahmen dieses Tutorials sprengen, das Python-Skript zu schreiben, um einen endgültigen Plot zu erstellen, daher stellen wir Ihnen das Skript als Teil dieser Lektion zur Verfügung. Sie können es herunterladen mit

BASH

curl -O https://ocaisa.github.io/hpc-workflows/files/plot_terse_amdahl_results.py

Das Skript plot_terse_amdahl_results.py benötigt eine Befehlszeile, die wie folgt aussieht:

BASH

python plot_terse_amdahl_results.py --output <output image filename> <1st input file> <2nd input file> ...

Lass uns das in unsere generate_run_files Regel einfügen:

PYTHON

rule generate_run_files:
    output: "p_{parallel_proportion}_runs.txt"
    input:  expand("p_{{parallel_proportion}}/runs/amdahl_run_{count}.json", count=NTASK_SIZES)
    shell:
        "python plot_terse_amdahl_results.py --output {output} {input}"

Aufgabe

Dieses Skript verlässt sich auf matplotlib, ist es als Umgebungsmodul verfügbar? Fügen Sie diese Bedingung zu unserer Regel hinzu.

PYTHON

rule generate_run_files:
    output: "p_{parallel_proportion}_scalability.jpg"
    input:  expand("p_{{parallel_proportion}}/runs/amdahl_run_{count}.json", count=NTASK_SIZES)
    envmodules:
      "matplotlib"
    shell:
        "python plot_terse_amdahl_results.py --output {output} {input}"

Jetzt können wir endlich ein Skalierungsdiagramm erstellen! Führen Sie den letzten Snakemake-Befehl aus:

BASH

snakemake --profile cluster_profile/ p_0.999_scalability.jpg

Aufgabe

Erzeugen Sie das Skalierbarkeitsdiagramm für alle Werte von 1 bis 10 Kernen.

PYTHON

NTASK_SIZES = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Aufgabe

Wiederholung des Arbeitsablaufs für einen p-Wert von 0,8

BASH

snakemake --profile cluster_profile/ p_0.8_scalability.jpg

Bonusrunde

Erstellen Sie eine endgültige Regel, die direkt aufgerufen werden kann und ein Skalierungsdiagramm für 3 verschiedene Werte von p erzeugt.

Hauptpunkte

  • “Verwenden Sie die Funktion expand(), um Listen von Dateinamen zu erzeugen, die Sie kombinieren wollen”
  • “Jede {input} zu einer Regel kann eine Liste variabler Länge sein”