Part 3: Hello Workflow¶
Traducció assistida per IA - més informació i suggeriments
Consulteu la llista de reproducció completa al canal de YouTube de Nextflow.
La transcripció del vídeo està disponible aquí.
La majoria de workflows del món real impliquen més d'un pas. En aquest mòdul de formació, aprendreu com connectar processos junts en un workflow de múltiples passos.
Això us ensenyarà la manera Nextflow d'aconseguir el següent:
- Fer que les dades flueixin d'un procés al següent
- Recollir sortides de múltiples crides de procés en una única crida de procés
- Passar paràmetres addicionals a un procés
- Gestionar múltiples sortides que surten d'un procés
Per demostrar-ho, continuarem construint sobre l'exemple Hello World independent del domini de les Parts 1 i 2. Aquesta vegada, farem els següents canvis al nostre workflow per reflectir millor com la gent construeix workflows reals:
- Afegir un segon pas que converteixi la salutació a majúscules.
- Afegir un tercer pas que reculli totes les salutacions transformades i les escrigui en un únic fitxer.
- Afegir un paràmetre per nomenar el fitxer de sortida final i passar-lo com a entrada secundària al pas de recollida.
- Fer que el pas de recollida també informi d'una estadística simple sobre el que s'ha processat.
Com començar des d'aquesta secció
Aquesta secció del curs assumeix que heu completat les Parts 1-2 del curs Hello Nextflow, però si us sentiu còmodes amb els conceptes bàsics coberts en aquestes seccions, podeu començar des d'aquí sense fer res especial.
0. Escalfament: Executeu hello-workflow.nf¶
Utilitzarem l'script de workflow hello-workflow.nf com a punt de partida.
És equivalent a l'script produït en treballar la Part 2 d'aquest curs de formació, excepte que hem eliminat les instruccions view() i hem canviat la destinació de sortida:
Aquest diagrama resumeix l'operació actual del workflow. Hauria de semblar familiar, excepte que ara estem mostrant explícitament que les sortides del procés s'empaqueten en un canal, igual que les entrades. Utilitzarem aquest canal de sortida en un moment.
Només per assegurar-nos que tot funciona, executeu l'script una vegada abans de fer cap canvi:
Sortida de la comanda
Com abans, trobareu els fitxers de sortida a la ubicació especificada al bloc output.
Per a aquest capítol, és sota results/hello_workflow/.
Contingut del directori
Si això us ha funcionat, esteu preparats per aprendre com muntar un workflow de múltiples passos.
1. Afegiu un segon pas al workflow¶
Afegirem un pas per convertir cada salutació a majúscules.
Per fer-ho, necessitem fer tres coses:
- Definir la comanda que utilitzarem per fer la conversió a majúscules.
- Escriure un nou procés que encapsuli la comanda de conversió a majúscules.
- Cridar el nou procés al bloc workflow i configurar-lo per prendre la sortida del procés
sayHello()com a entrada.
1.1. Definiu la comanda de conversió a majúscules i proveu-la al terminal¶
Per fer la conversió de les salutacions a majúscules, utilitzarem una eina UNIX clàssica anomenada tr per 'text replacement', amb la següent sintaxi:
Aquesta és una substitució de text molt naïf que no té en compte les lletres accentuades, així que per exemple 'Holà' es convertirà en 'HOLà', però farà una feina prou bona per demostrar els conceptes de Nextflow i això és el que importa.
Per provar-ho, podem executar la comanda echo 'Hello World' i canalitzar la seva sortida a la comanda tr:
La sortida és un fitxer de text anomenat UPPER-output.txt que conté la versió en majúscules de la cadena Hello World.
Això és bàsicament el que intentarem fer amb el nostre workflow.
1.2. Escriviu el pas de conversió a majúscules com a procés Nextflow¶
Podem modelar el nostre nou procés sobre el primer, ja que volem utilitzar tots els mateixos components.
Afegiu la següent definició de procés a l'script de workflow, just sota el primer:
| hello-workflow.nf | |
|---|---|
En aquest, compondrem el segon nom de fitxer de sortida basat en el nom del fitxer d'entrada, de manera similar al que vam fer originalment per a la sortida del primer procés.
1.3. Afegiu una crida al nou procés al bloc workflow¶
Ara necessitem dir a Nextflow que realment cridi el procés que acabem de definir.
Al bloc workflow, feu el següent canvi de codi:
| hello-workflow.nf | |
|---|---|
Això encara no és funcional perquè no hem especificat què hauria de ser l'entrada del procés convertToUpper().
1.4. Passeu la sortida del primer procés al segon procés¶
Ara necessitem fer que la sortida del procés sayHello() flueixi cap al procés convertToUpper().
Convenientment, Nextflow empaqueta automàticament la sortida d'un procés en un canal, com es mostra al diagrama de la secció d'escalfament.
Podem referir-nos al canal de sortida d'un procés com <process>.out.
Així doncs, la sortida del procés sayHello és un canal anomenat sayHello.out, que podem connectar directament a la crida a convertToUpper().
Al bloc workflow, feu el següent canvi de codi:
Per a un cas simple com aquest (una sortida a una entrada), això és tot el que necessitem fer per connectar dos processos!
1.5. Configureu la publicació de sortida del workflow¶
Finalment, actualitzem les sortides del workflow per publicar també els resultats del segon procés.
1.5.1. Actualitzeu la secció publish: del bloc workflow¶
Al bloc workflow, feu el següent canvi de codi:
La lògica és la mateixa que abans.
1.5.2. Actualitzeu el bloc output¶
Al bloc output, feu el següent canvi de codi:
Una vegada més, la lògica és la mateixa que abans.
Això us mostra que podeu controlar la configuració de sortida a un nivell molt granular, per a cada sortida individual. Sentiu-vos lliures de provar canviar els camins o el mode de publicació per a un dels processos per veure què passa.
Per descomptat, això significa que estem repetint alguna informació aquí, que podria esdevenir inconvenient si volguéssim actualitzar la ubicació per a totes les sortides de la mateixa manera. Més endavant al curs, aprendreu com configurar aquests paràmetres per a múltiples sortides de manera estructurada.
1.6. Executeu el workflow amb -resume¶
Provem això utilitzant la bandera -resume, ja que ja hem executat el primer pas del workflow amb èxit.
Sortida de la comanda
Ara hi ha una línia extra a la sortida de la consola que correspon al nou procés que acabem d'afegir.
Trobareu les sortides al directori results/hello_workflow tal com s'ha establert al bloc output.
Contingut del directori
Això és convenient! Però encara val la pena donar una ullada dins del directori de treball d'una de les crides al segon procés.
Contingut del directori
Observeu que hi ha dos fitxers *-output: la sortida del primer procés així com la sortida del segon.
La sortida del primer procés hi és perquè Nextflow la va preparar allà per tenir tot el necessari per a l'execució dins del mateix subdirectori.
No obstant això, en realitat és un enllaç simbòlic que apunta al fitxer original al subdirectori de la primera crida de procés. Per defecte, quan s'executa en una sola màquina com estem fent aquí, Nextflow utilitza enllaços simbòlics en lloc de còpies per preparar fitxers d'entrada i intermedis.
Ara, abans de continuar, penseu en com tot el que vam fer va ser connectar la sortida de sayHello a l'entrada de convertToUpper i els dos processos es van poder executar en sèrie.
Nextflow va fer la feina dura de gestionar fitxers d'entrada i sortida individuals i passar-los entre les dues comandes per nosaltres.
Aquesta és una de les raons per les quals els canals de Nextflow són tan potents: s'encarreguen de la feina rutinària implicada en connectar passos de workflow junts.
Conclusió¶
Sabeu com encadenar processos junts proporcionant la sortida d'un pas com a entrada al següent pas.
Què segueix?¶
Apreneu com recollir sortides de crides de procés per lots i alimentar-les en un únic procés.
2. Afegiu un tercer pas per recollir totes les salutacions¶
Quan utilitzem un procés per aplicar una transformació a cadascun dels elements d'un canal, com estem fent aquí amb les múltiples salutacions, de vegades volem recollir elements del canal de sortida d'aquest procés i alimentar-los en un altre procés que realitza algun tipus d'anàlisi o sumatori.
Per demostrar-ho, afegirem un nou pas al nostre pipeline que reculli totes les salutacions en majúscules produïdes pel procés convertToUpper i les escrigui en un únic fitxer.
Per no espatllar la sorpresa, però això implicarà un operador molt útil.
2.1. Definiu la comanda de recollida i proveu-la al terminal¶
El pas de recollida que volem afegir al nostre workflow utilitzarà la comanda cat per concatenar múltiples salutacions en majúscules en un únic fitxer.
Executem la comanda per si sola al terminal per verificar que funciona com s'espera, igual que hem fet abans.
Executeu el següent al vostre terminal:
echo 'Hello' | tr '[a-z]' '[A-Z]' > UPPER-Hello-output.txt
echo 'Bonjour' | tr '[a-z]' '[A-Z]' > UPPER-Bonjour-output.txt
echo 'Holà' | tr '[a-z]' '[A-Z]' > UPPER-Holà-output.txt
cat UPPER-Hello-output.txt UPPER-Bonjour-output.txt UPPER-Holà-output.txt > COLLECTED-output.txt
La sortida és un fitxer de text anomenat COLLECTED-output.txt que conté les versions en majúscules de les salutacions originals.
Aquest és el resultat que volem aconseguir amb el nostre workflow.
2.2. Creeu un nou procés per fer el pas de recollida¶
Creem un nou procés i l'anomenem collectGreetings().
Podem començar a escriure'l basat en el que hem vist abans.
2.2.1. Escriviu les parts 'òbvies' del procés¶
Afegiu la següent definició de procés a l'script de workflow:
| hello-workflow.nf | |
|---|---|
Això és el que podem escriure amb confiança basat en el que heu après fins ara. Però això no és funcional! Deixa de banda la(es) definició(ns) d'entrada i la primera meitat de la comanda script perquè necessitem esbrinar com escriure-ho.
2.2.2. Definiu les entrades a collectGreetings()¶
Necessitem recollir les salutacions de totes les crides al procés convertToUpper().
Què sabem que podem obtenir del pas anterior al workflow?
El canal de sortida de convertToUpper() contindrà els camins als fitxers individuals que contenen les salutacions en majúscules.
Això equival a una ranura d'entrada; anomenem-la input_files per simplicitat.
Al bloc de procés, feu el següent canvi de codi:
Observeu que utilitzem el prefix path encara que esperem que això contingui múltiples fitxers.
2.2.3. Compondreu la comanda de concatenació¶
Aquí és on les coses podrien complicar-se una mica, perquè necessitem poder gestionar un nombre arbitrari de fitxers d'entrada. Específicament, no podem escriure la comanda per endavant, així que necessitem dir a Nextflow com compondre-la en temps d'execució basat en quines entrades flueixen cap al procés.
En altres paraules, si tenim un canal d'entrada que conté l'element [file1.txt, file2.txt, file3.txt], necessitem que Nextflow ho converteixi en cat file1.txt file2.txt file3.txt.
Afortunadament, Nextflow està molt content de fer-ho per nosaltres si simplement escrivim cat ${input_files} a la comanda script.
Al bloc de procés, feu el següent canvi de codi:
En teoria això hauria de gestionar qualsevol nombre arbitrari de fitxers d'entrada.
Consell
Algunes eines de línia de comandes requereixen proporcionar un argument (com -input) per a cada fitxer d'entrada.
En aquest cas, hauríem de fer una mica de feina extra per compondre la comanda.
Podeu veure un exemple d'això al curs de formació Nextflow for Genomics.
2.3. Afegiu el pas de recollida al workflow¶
Ara només hauríem de necessitar cridar el procés de recollida sobre la sortida del pas de conversió a majúscules.
Això també és un canal, anomenat convertToUpper.out.
2.3.1. Connecteu les crides de procés¶
Al bloc workflow, feu el següent canvi de codi:
Això connecta la sortida de convertToUpper() a l'entrada de collectGreetings().
2.3.2. Executeu el workflow amb -resume¶
Provem-ho.
Sortida de la comanda
S'executa amb èxit, incloent el tercer pas.
No obstant això, mireu el nombre de crides per a collectGreetings() a l'última línia.
Només esperàvem una, però n'hi ha tres.
Ara doneu una ullada al contingut del fitxer de sortida final.
Oh no. El pas de recollida es va executar individualment en cada salutació, que NO és el que volíem.
Necessitem fer alguna cosa per dir a Nextflow explícitament que volem que aquest tercer pas s'executi sobre tots els elements del canal de sortida de convertToUpper().
2.4. Utilitzeu un operador per recollir les salutacions en una única entrada¶
Sí, una vegada més la resposta al nostre problema és un operador.
Específicament, utilitzarem l'operador amb el nom apropiat collect().
2.4.1. Afegiu l'operador collect()¶
Aquesta vegada semblarà una mica diferent perquè no estem afegint l'operador en el context d'una factoria de canals; l'estem afegint a un canal de sortida.
Prenem el convertToUpper.out i afegim l'operador collect(), que ens dóna convertToUpper.out.collect().
Podem connectar això directament a la crida del procés collectGreetings().
Al bloc workflow, feu el següent canvi de codi:
2.4.2. Afegiu algunes instruccions view()¶
També inclourem un parell d'instruccions view() per visualitzar els estats abans i després del contingut del canal.
| hello-workflow.nf | |
|---|---|
Les instruccions view() poden anar on vulgueu; les hem posat just després de la crida per llegibilitat.
2.4.3. Executeu el workflow de nou amb -resume¶
Provem-ho:
Sortida de la comanda
N E X T F L O W ~ version 25.10.2
Launching `hello-workflow.nf` [soggy_franklin] DSL2 - revision: bc8e1b2726
[d6/cdf466] sayHello (1) | 3 of 3, cached: 3 ✔
[99/79394f] convertToUpper (2) | 3 of 3, cached: 3 ✔
[1e/83586c] collectGreetings | 1 of 1 ✔
Before collect: /workspaces/training/hello-nextflow/work/b3/d52708edba8b864024589285cb3445/UPPER-Bonjour-output.txt
Before collect: /workspaces/training/hello-nextflow/work/99/79394f549e3040dfc2440f69ede1fc/UPPER-Hello-output.txt
Before collect: /workspaces/training/hello-nextflow/work/aa/56bfe7cf00239dc5badc1d04b60ac4/UPPER-Holà-output.txt
After collect: [/workspaces/training/hello-nextflow/work/b3/d52708edba8b864024589285cb3445/UPPER-Bonjour-output.txt, /workspaces/training/hello-nextflow/work/99/79394f549e3040dfc2440f69ede1fc/UPPER-Hello-output.txt, /workspaces/training/hello-nextflow/work/aa/56bfe7cf00239dc5badc1d04b60ac4/UPPER-Holà-output.txt]
S'executa amb èxit, encara que la sortida del registre pot semblar una mica més desordenada que això (l'hem netejat per llegibilitat).
Aquesta vegada el tercer pas només es va cridar una vegada!
Mirant la sortida de les instruccions view(), veiem el següent:
- Tres instruccions
Abans de collect:, una per a cada salutació: en aquest punt els camins de fitxer són elements individuals al canal. - Una única instrucció
Després de collect:: els tres camins de fitxer ara estan empaquetats en un únic element.
Podem resumir això amb el següent diagrama:
Finalment, podeu donar una ullada al contingut del fitxer de sortida per satisfer-vos que tot ha funcionat correctament.
Aquesta vegada tenim les tres salutacions al fitxer de sortida final. Èxit!
Nota
Si executeu això diverses vegades sense -resume, veureu que l'ordre de les salutacions canvia d'una execució a la següent.
Això us mostra que l'ordre en què els elements flueixen a través de les crides de procés no està garantit que sigui consistent.
2.4.4. Elimineu les instruccions view() per llegibilitat¶
Abans de passar a la següent secció, us recomanem que elimineu les instruccions view() per evitar embolicar la sortida de la consola.
| hello-workflow.nf | |
|---|---|
Això és bàsicament l'operació inversa del punt 2.4.2.
Conclusió¶
Sabeu com recollir sortides d'un lot de crides de procés i alimentar-les en un pas d'anàlisi o sumatori conjunt.
Per recapitular, això és el que heu construït fins ara:
Què segueix?¶
Apreneu com passar més d'una entrada a un procés.
3. Passeu paràmetres addicionals a un procés¶
Volem poder nomenar el fitxer de sortida final alguna cosa específica per poder processar lots posteriors de salutacions sense sobreescriure els resultats finals.
Per fer-ho, farem els següents refinaments al workflow:
- Modificar el procés col·lector per acceptar un nom definit per l'usuari per al fitxer de sortida (
batch_name) - Afegir un paràmetre de línia de comandes al workflow (
--batch) i passar-lo al procés col·lector
3.1. Modifiqueu el procés col·lector¶
Necessitarem declarar l'entrada addicional i integrar-la al nom del fitxer de sortida.
3.1.1. Declareu l'entrada addicional¶
Bones notícies: podem declarar tantes variables d'entrada com vulguem a la definició del procés.
Anomenem aquesta batch_name.
Al bloc de procés, feu el següent canvi de codi:
Podeu configurar els vostres processos per esperar tantes entrades com vulgueu. Ara mateix, totes estan configurades per ser entrades requerides; heu de proporcionar un valor perquè el workflow funcioni.
Aprendreu com gestionar entrades requerides vs. opcionals més endavant al vostre viatge amb Nextflow.
3.1.2. Utilitzeu la variable batch_name al nom del fitxer de sortida¶
Podem inserir la variable al nom del fitxer de sortida de la mateixa manera que hem compost noms de fitxer dinàmics abans.
Al bloc de procés, feu el següent canvi de codi:
Això configura el procés per utilitzar el valor batch_name per generar un nom de fitxer específic per a la sortida final del workflow.
3.2. Afegiu un paràmetre de línia de comandes batch¶
Ara necessitem una manera de subministrar el valor per a batch_name i alimentar-lo a la crida del procés.
3.2.1. Utilitzeu params per configurar el paràmetre¶
Ja sabeu com utilitzar el sistema params per declarar paràmetres CLI.
Utilitzem això per declarar un paràmetre batch (amb un valor per defecte perquè som mandrosos).
A la secció de paràmetres del pipeline, feu els següents canvis de codi:
Igual que vam demostrar per a --input, podeu sobreescriure aquest valor per defecte especificant un valor amb --batch a la línia de comandes.
3.2.2. Passeu el paràmetre batch al procés¶
Per proporcionar el valor del paràmetre al procés, necessitem afegir-lo a la crida del procés.
Al bloc workflow, feu el següent canvi de codi:
Veieu que per proporcionar múltiples entrades a un procés, simplement les llisteu als parèntesis de la crida, separades per comes.
Advertència
HEU de proporcionar les entrades al procés en el MATEIX ORDRE EXACTE en què estan llistades al bloc de definició d'entrada del procés.
3.3. Executeu el workflow¶
Provem d'executar això amb un nom de lot a la línia de comandes.
Sortida de la comanda
S'executa amb èxit i produeix la sortida desitjada:
Ara, sempre que especifiquem el paràmetre adequadament, execucions posteriors sobre altres lots d'entrades no sobreescriuran resultats anteriors.
Conclusió¶
Sabeu com passar més d'una entrada a un procés.
Què segueix?¶
Apreneu com emetre múltiples sortides i gestionar-les convenientment.
4. Afegiu una sortida al pas col·lector¶
Fins ara hem estat utilitzant processos que només produïen una sortida cadascun.
Vam poder accedir a les seves respectives sortides molt convenientment utilitzant la sintaxi <process>.out, que vam utilitzar tant en el context de passar una sortida al següent procés (p. ex. convertToUpper(sayHello.out)) com en el context de la secció publish: (p. ex. first_output = sayHello.out).
Què passa quan un procés produeix més d'una? Com gestionem les múltiples sortides? Podem seleccionar i utilitzar una sortida específica?
Totes preguntes excel·lents, i la resposta curta és que sí que podem!
Les múltiples sortides s'empaquetaran en canals separats. Podem optar per donar noms a aquests canals de sortida, cosa que facilita referir-nos-hi individualment més endavant, o podem referir-nos-hi per índex.
Per propòsits de demostració, diguem que volem comptar el nombre de salutacions que s'estan recollint per a un lot donat d'entrades i informar-ho en un fitxer.
4.1. Modifiqueu el procés per comptar i emetre el nombre de salutacions¶
Això requerirà dos canvis clau a la definició del procés: necessitem una manera de comptar les salutacions i escriure un fitxer d'informe, després necessitem afegir aquest fitxer d'informe al bloc output del procés.
4.1.1. Compteu el nombre de salutacions recollides¶
Convenientment, Nextflow ens permet afegir codi arbitrari al bloc script: de la definició del procés, cosa que és molt útil per fer coses com aquesta.
Això significa que podem utilitzar la funció integrada de Nextflow size() per obtenir el nombre de fitxers a l'array input_files, i escriure el resultat a un fitxer amb una comanda echo.
Al bloc de procés collectGreetings, feu els següents canvis de codi:
La variable count_greetings es calcularà en temps d'execució.
4.1.2. Emeteu el fitxer d'informe i anomeneu les sortides¶
En principi tot el que necessitem fer és afegir el fitxer d'informe al bloc output:.
No obstant això, mentre hi som, també afegirem algunes etiquetes emit: a les nostres declaracions de sortida. Aquestes ens permetran seleccionar les sortides per nom en lloc d'haver d'utilitzar índexs posicionals.
Al bloc de procés, feu el següent canvi de codi:
Les etiquetes emit: són opcionals, i podríem haver afegit una etiqueta només a una de les sortides.
Però com diu el refrany, per què no ambdues?
Consell
Si no anomeneu les sortides d'un procés utilitzant emit:, encara podeu accedir-hi individualment utilitzant el seu respectiu índex (basat en zero).
Per exemple, utilitzaríeu <process>.out[0] per obtenir la primera sortida, <process>.out[1] per obtenir la segona sortida, i així successivament.
Preferim anomenar les sortides perquè altrament, és massa fàcil agafar l'índex equivocat per error, especialment quan el procés produeix moltes sortides.
4.2. Actualitzeu les sortides del workflow¶
Ara que tenim dues sortides sortint del procés collectGreetings, la sortida collectGreetings.out conté dos canals:
collectGreetings.out.outfileconté el fitxer de sortida finalcollectGreetings.out.reportconté el fitxer d'informe
Necessitem actualitzar les sortides del workflow en conseqüència.
4.2.1. Actualitzeu la secció publish:¶
Al bloc workflow, feu el següent canvi de codi:
Com podeu veure, referir-se a sortides de procés específiques ara és trivial.
Quan anem a afegir un pas més al nostre pipeline a la Part 5 (Contenidors), podrem referir-nos fàcilment a collectGreetings.out.outfile i passar-lo al nou procés (spoiler: el nou procés s'anomena cowpy).
Però per ara, acabem d'actualitzar les sortides a nivell de workflow.
4.2.2. Actualitzeu el bloc output¶
Al bloc output, feu el següent canvi de codi:
No necessitem actualitzar la definició de sortida collected ja que aquest nom no ha canviat.
Només necessitem afegir la nova sortida.
4.3. Executeu el workflow¶
Provem d'executar això amb el lot actual de salutacions.
Sortida de la comanda
Si mireu al directori results/hello_workflow/, trobareu el nou fitxer d'informe, trio-report.txt.
Obriu-lo per verificar que el workflow va informar correctament del recompte de salutacions que es van processar.
Sentiu-vos lliures d'afegir més salutacions al CSV i provar què passa.
Conclusió¶
Sabeu com fer que un procés emeti múltiples sortides amb nom i com gestionar-les adequadament a nivell de workflow.
Més generalment, enteneu els principis clau implicats en connectar processos junts de maneres comunes.
Què segueix?¶
Preneu-vos un descans extra llarg, us l'heu guanyat.
Quan estigueu preparats, passeu a Part 4: Hello Modules per aprendre com modularitzar el vostre codi per a una millor mantenibilitat i eficiència del codi.
Qüestionari¶
Com accediu a la sortida d'un procés al bloc workflow?
Què determina l'ordre d'execució dels processos a Nextflow?
Quan hauríeu d'utilitzar l'operador collect()?
Com accediu a una sortida amb nom d'un procés?
Quina és la sintaxi correcta per anomenar una sortida en un procés?
Quan proporcioneu múltiples entrades a un procés, què ha de ser cert?