Salta el contingut

Part 2: Reescriure Hello per a nf-core

Traducció assistida per IA - més informació i suggeriments

En aquesta segona part del curs de formació Hello nf-core, us mostrem com crear una versió compatible amb nf-core del pipeline produït pel curs per a principiants Hello Nextflow.

Ho farem en dues fases: primer, utilitzarem les eines nf-core per crear una estructura de pipeline, i després injectarem el codi del pipeline 'regular' existent a aquesta estructura.

Si no esteu familiaritzats amb el pipeline Hello o us caldria un recordatori, consulteu aquesta pàgina d'informació.

Consell

Aquesta part del curs introduirà dos mecanismes importants de Nextflow que no es cobreixen al curs introductori Hello Nextflow: els meta maps i els workflows of workflows, tots dos tractats en detall a les Side Quests enllaçades.

Les instruccions següents inclouen la informació essencial que necessiteu per entendre com s'utilitzen en el context nf-core, però pot ser molt per assimilar d'una vegada. Si teniu temps, us recomanem treballar primer les dues Side Quests (en qualsevol ordre):

Nota

Assegureu-vos que esteu al directori hello-nf-core al vostre terminal.


1. Examinar l'estructura del codi del pipeline

El projecte nf-core aplica directrius estrictes sobre com s'estructuren els pipelines i com s'organitza, configura i documenta el codi.

Abans d'abordar el nostre projecte de creació de pipeline, hem d'entendre aquesta estructura i organització. Així doncs, donem una ullada a com s'organitza el codi del pipeline al repositori nf-core/demo, utilitzant l'enllaç simbòlic pipelines que vam crear a la Part 1.

Com a recordatori, podeu utilitzar tree o l'explorador de fitxers per trobar i obrir el directori nf-core/demo.

tree -L 1 pipelines/nf-core/demo
Contingut del directori
pipelines/nf-core/demo
├── assets
├── CHANGELOG.md
├── CITATIONS.md
├── CODE_OF_CONDUCT.md
├── conf
├── docs
├── LICENSE
├── main.nf
├── modules
├── modules.json
├── nextflow.config
├── nextflow_schema.json
├── nf-test.config
├── README.md
├── ro-crate-metadata.json
├── subworkflows
├── tests
├── tower.yml
└── workflows

De moment ens centrarem específicament en els components del codi del pipeline (main.nf, workflows, subworkflows, modules) i com es relacionen entre ells.

1.1. Estructura modular dels workflows nf-core

L'organització estàndard del codi d'un pipeline nf-core segueix una estructura modular dissenyada per maximitzar la reutilització del codi, tal com s'introdueix a Hello Modules, la Part 4 del curs Hello Nextflow, tot i que a l'estil nf-core, això s'implementa amb una mica de complexitat addicional. Concretament, els pipelines nf-core fan un ús abundant de subworkflows, és a dir, scripts de workflow que són importats per un workflow pare.

Pot semblar una mica abstracte, així que vegem com s'utilitza a la pràctica al pipeline nf-core/demo.

Si mireu dins del fitxer main.nf, veureu que importa un workflow anomenat DEMO de workflows/demo.nf, així com alguns mòduls i subworkflows.

Aquí teniu com es veuen les relacions entre els components de codi rellevants:

subworkflows/workflows/demo.nffastqc/main.nfmultiqc/main.nfseqtk/trim/main.nfmain.nfincludeincludemodules/nf-core/local/utils_nfcore_demo_pipeline/main.nfnf-core/utils_*/main.nf

El workflow sense nom a main.nf s'anomena script entrypoint. Actua com a embolcall per a dos tipus de workflows niats: el workflow DEMO que conté la lògica d'anàlisi real, ubicat a workflows/demo.nf, i un conjunt de workflows de manteniment ubicats sota subworkflows/. El workflow demo.nf crida mòduls ubicats sota modules/; aquests contenen els processos que realitzaran els passos d'anàlisi reals.

Nota

Els subworkflows no es limiten a funcions de manteniment, i poden fer ús de mòduls de processos.

El pipeline nf-core/demo que es mostra aquí és relativament senzill, però altres pipelines nf-core (com nf-core/rnaseq) utilitzen subworkflows que participen en l'anàlisi real.

Ara revisem aquests components en detall.

1.2. L'script entrypoint: main.nf

L'script main.nf és el punt d'entrada des d'on Nextflow comença quan executem nextflow run nf-core/demo. Això significa que quan executeu nextflow run nf-core/demo per executar el pipeline, Nextflow troba i executa automàticament l'script main.nf. Això funciona per a qualsevol pipeline Nextflow que segueixi aquesta nomenclatura i estructura convencionals, no només els pipelines nf-core.

Utilitzar un script entrypoint facilita l'execució de subworkflows de 'manteniment' estandarditzats abans i després que s'executi l'script d'anàlisi real. Revisarem aquests un cop haguem examinat el workflow d'anàlisi real i els seus mòduls.

1.3. L'script d'anàlisi: workflows/demo.nf

El workflow workflows/demo.nf és on s'emmagatzema la lògica central del pipeline. Està estructurat de manera similar a un workflow Nextflow normal, excepte que està dissenyat per ser cridat des d'un workflow pare, cosa que requereix algunes funcionalitats addicionals. Cobrirem les diferències rellevants a la següent part d'aquest curs, quan abordem la conversió del pipeline Hello simple de Hello Nextflow a una forma compatible amb nf-core.

El workflow demo.nf crida mòduls ubicats sota modules/, que revisarem a continuació.

Nota

Alguns workflows d'anàlisi nf-core mostren nivells addicionals de niament cridant subworkflows de nivell inferior. Això s'utilitza principalment per agrupar dos o més mòduls que s'utilitzen habitualment junts en segments de pipeline fàcilment reutilitzables. Podeu veure alguns exemples navegant pels subworkflows nf-core disponibles al lloc web nf-core.

Quan l'script d'anàlisi utilitza subworkflows, aquests s'emmagatzemen sota el directori subworkflows/.

1.4. Els mòduls

Els mòduls són on viu el codi dels processos, tal com es descriu a la Part 4 del curs de formació Hello Nextflow.

Al projecte nf-core, els mòduls s'organitzen utilitzant una estructura niada de múltiples nivells que reflecteix tant el seu origen com el seu contingut. Al nivell superior, els mòduls es diferencien com a nf-core o local (no formen part del projecte nf-core), i després es col·loquen en un directori amb el nom de les eines que encapsulen. Si l'eina pertany a un toolkit (és a dir, un paquet que conté múltiples eines), hi ha un nivell de directori intermedi amb el nom del toolkit.

Podeu veure això aplicat a la pràctica als mòduls del pipeline nf-core/demo:

tree -L 3 pipelines/nf-core/demo/modules
Contingut del directori
pipelines/nf-core/demo/modules
└── nf-core
    ├── fastqc
    │   ├── environment.yml
    │   ├── main.nf
    │   ├── meta.yml
    │   └── tests
    ├── multiqc
    │   ├── environment.yml
    │   ├── main.nf
    │   ├── meta.yml
    │   └── tests
    └── seqtk
        └── trim

7 directories, 6 files

Aquí veieu que els mòduls fastqc i multiqc es troben al nivell superior dins dels mòduls nf-core, mentre que el mòdul trim es troba sota el toolkit al qual pertany, seqtk. En aquest cas no hi ha mòduls local.

El fitxer de codi del mòdul que descriu el procés sempre s'anomena main.nf, i va acompanyat de tests i fitxers .yml que ignorarem per ara.

En conjunt, el workflow entrypoint, el workflow d'anàlisi i els mòduls són suficients per executar les parts 'interessants' del pipeline. No obstant això, sabem que també hi ha subworkflows de manteniment, així que donem-hi una ullada ara.

1.5. Els subworkflows de manteniment

Com els mòduls, els subworkflows es diferencien en directoris local i nf-core, i cada subworkflow té la seva pròpia estructura de directori niada amb el seu propi script main.nf, tests i fitxer .yml.

tree -L 3 pipelines/nf-core/demo/subworkflows
Contingut del directori
pipelines/nf-core/demo/subworkflows
├── local
│   └── utils_nfcore_demo_pipeline
│       └── main.nf
└── nf-core
    ├── utils_nextflow_pipeline
    │   ├── main.nf
    │   ├── meta.yml
    │   └── tests
    ├── utils_nfcore_pipeline
    │   ├── main.nf
    │   ├── meta.yml
    │   └── tests
    └── utils_nfschema_plugin
        ├── main.nf
        ├── meta.yml
        └── tests

9 directories, 7 files

Com s'ha indicat anteriorment, el pipeline nf-core/demo no inclou cap subworkflow específic d'anàlisi, de manera que tots els subworkflows que veiem aquí són els anomenats workflows de 'manteniment' o 'utilitat', tal com indica el prefix utils_ als seus noms. Aquests subworkflows són els que produeixen la capçalera nf-core elegant a la sortida de la consola, entre altres funcions accessòries.

Consell

A part del seu patró de nomenclatura, una altra indicació que aquests subworkflows no realitzen cap funció realment relacionada amb l'anàlisi és que no criden cap procés.

Això completa el repàs dels components de codi principals que constitueixen el pipeline nf-core/demo.

Conclusió

Ara teniu una comprensió d'alt nivell de l'estructura modular dels pipelines nf-core.

Què segueix?

Creeu una estructura de pipeline utilitzant les eines nf-core.


2. Crear un nou projecte de pipeline

Com heu vist, els pipelines nf-core segueixen una estructura estandarditzada amb molts fitxers accessoris. Crear tot això des de zero seria molt tediós, així que la comunitat nf-core ha desenvolupat eines per fer-ho a partir d'una plantilla, per iniciar el procés.

2.1. Executar l'eina de creació de pipelines basada en plantilla

Comencem creant un nou pipeline amb la comanda nf-core pipelines create. Això crearà una nova estructura de pipeline utilitzant la plantilla base nf-core, personalitzada amb un nom de pipeline, descripció i autor.

nf-core pipelines create

Executar aquesta comanda obrirà una Interfície d'Usuari de Text (TUI) per a la creació del pipeline:

Aquesta TUI us demanarà que proporcioneu informació bàsica sobre el vostre pipeline i us oferirà una selecció de funcionalitats per incloure o excloure a l'estructura del vostre pipeline.

  • A la pantalla de benvinguda, feu clic a Let's go!.
  • A la pantalla Choose pipeline type, feu clic a Custom.
  • Introduïu els detalls del vostre pipeline de la següent manera (substituint < YOUR NAME > pel vostre propi nom), després feu clic a Next.
[ ] GitHub organisation: core
[ ] Workflow name: hello
[ ] A short description of your pipeline: A basic nf-core style version of Hello Nextflow
[ ] Name of the main author(s): < YOUR NAME >
  • A la pantalla Template features, establiu Toggle all features a off, després activeu selectivament els següents. Comproveu les vostres seleccions i feu clic a Continue.
[ ] Add testing profiles
[ ] Use nf-core components
[ ] Use nf-schema
[ ] Add configuration files
[ ] Add documentation
  • A la pantalla Final details, feu clic a Finish. Espereu que es creï el pipeline, després feu clic a Continue.
  • A la pantalla Create GitHub repository, feu clic a Finish without creating a repo. Això mostrarà instruccions per crear un repositori GitHub més endavant. Ignoreu-les i feu clic a Close.

Un cop es tanqui la TUI, hauríeu de veure la següent sortida a la consola.

Sortida de la comanda
                                          ,--./,-.
          ___     __   __   __   ___     /,-._.--~\
    |\ | |__  __ /  ` /  \ |__) |__         }  {
    | \| |       \__, \__/ |  \ |___     \`-._,-`-,
                                          `._,._,'

    nf-core/tools version 3.5.2 - https://nf-co.re


INFO     Launching interactive nf-core pipeline creation tool.

No hi ha cap confirmació explícita a la sortida de la consola que la creació del pipeline hagi funcionat, però hauríeu de veure un nou directori anomenat core-hello.

Visualitzeu el contingut del nou directori per veure quanta feina us heu estalviat utilitzant la plantilla.

tree core-hello
Contingut del directori
core-hello/
├── README.md
├── assets
│   ├── samplesheet.csv
│   └── schema_input.json
├── conf
│   ├── base.config
│   ├── modules.config
│   ├── test.config
│   └── test_full.config
├── docs
│   ├── README.md
│   ├── output.md
│   └── usage.md
├── main.nf
├── modules.json
├── nextflow.config
├── nextflow_schema.json
├── subworkflows
│   ├── local
│   │   └── utils_nfcore_hello_pipeline
│   │       └── main.nf
│   └── nf-core
│       ├── utils_nextflow_pipeline
│       │   ├── main.nf
│       │   ├── meta.yml
│       │   └── tests
│       │       ├── main.function.nf.test
│       │       ├── main.function.nf.test.snap
│       │       ├── main.workflow.nf.test
│       │       └── nextflow.config
│       ├── utils_nfcore_pipeline
│       │   ├── main.nf
│       │   ├── meta.yml
│       │   └── tests
│       │       ├── main.function.nf.test
│       │       ├── main.function.nf.test.snap
│       │       ├── main.workflow.nf.test
│       │       ├── main.workflow.nf.test.snap
│       │       └── nextflow.config
│       └── utils_nfschema_plugin
│           ├── main.nf
│           ├── meta.yml
│           └── tests
│               ├── main.nf.test
│               ├── nextflow.config
│               └── nextflow_schema.json
└── workflows
    └── hello.nf

15 directories, 34 files

Són molts fitxers! No us preocupeu si us sentiu una mica perduts; recorrerem les parts importants aviat, i després pas a pas durant la resta del curs.

En general, això hauria de semblar similar a l'estructura de codi que vam observar per al pipeline nf-core/demo, excepte que aquí no hi ha cap directori modules.

2.2. Comprovar que l'estructura és funcional

Cregueu-ho o no, tot i que encara no heu afegit cap mòdul per fer-lo fer feina real, l'estructura del pipeline es pot executar utilitzant el perfil de test, de la mateixa manera que vam executar el pipeline nf-core/demo.

nextflow run ./core-hello -profile docker,test --outdir core-hello-results
Sortida de la comanda
N E X T F L O W   ~  version 25.10.4

Launching `./core-hello/main.nf` [scruffy_marconi] DSL2 - revision: b9e9b3b8de

Downloading plugin nf-schema@2.5.1
Input/output options
  input                     : https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv
  outdir                    : core-hello-results

Institutional config options
  config_profile_name       : Test profile
  config_profile_description: Minimal test dataset to check pipeline function

Generic options
  trace_report_suffix       : 2025-11-21_04-47-18

Core Nextflow options
  runName                   : scruffy_marconi
  containerEngine           : docker
  launchDir                 : /workspaces/training/hello-nf-core
  workDir                   : /workspaces/training/hello-nf-core/work
  projectDir                : /workspaces/training/hello-nf-core/core-hello
  userName                  : root
  profile                   : docker,test
  configFiles               : /workspaces/training/hello-nf-core/core-hello/nextflow.config

!! Only displaying parameters that differ from the pipeline defaults !!
------------------------------------------------------
-[core/hello] Pipeline completed successfully-

Això us mostra que tot el cablejat bàsic està en el seu lloc. Així doncs, on són les sortides? N'hi ha cap?

De fet, es va crear un nou directori de resultats anomenat core-hello-results que conté els informes d'execució estàndard:

tree core-hello-results
Contingut del directori
core-hello-results
└── pipeline_info
    ├── execution_report_2025-11-21_04-47-18.html
    ├── execution_timeline_2025-11-21_04-47-18.html
    ├── execution_trace_2025-11-21_04-47-18.txt
    ├── hello_software_versions.yml
    ├── params_2025-11-21_04-47-18.json
    └── pipeline_dag_2025-11-21_04-47-18.html

1 directory, 6 files

Podeu donar una ullada als informes per veure què s'ha executat, i la resposta és: res en absolut!

informe de línia de temps d'execució buit

Donem una ullada més detallada al que hi ha realment dins.

2.3. Examinar l'estructura de l'estructura del pipeline

Si recordeu l'estructura del pipeline nf-core/demo, hi havia un fitxer main.nf que contenia un workflow entrypoint que embolcallava el workflow DEMO. Ara si obriu el fitxer main.nf al vostre projecte recentment creat, veureu que importa un workflow anomenat HELLO de workflows/hello.nf. Això és l'equivalent directe al workflow DEMO, tot i que de moment és només un marcador de posició.

I en conseqüència, aquesta és l'estructura general de l'estructura del pipeline:

subworkflows/workflows/hello.nfmain.nfincludelocal/utils_nfcore_demo_pipeline/main.nfnf-core/utils_*/main.nf

Això us hauria de recordar l'estructura del pipeline nf-core/demo! L'única diferència real és que el workflow DEMO incloïa processos de mòduls. Aquí, el workflow HELLO equivalent encara no inclou cap procés.

Donem-hi una ullada més detallada.

2.4. Examinar el workflow de marcador de posició

Això serveix com a marcador de posició per al nostre workflow d'anàlisi, amb alguna funcionalitat nf-core ja en el seu lloc.

core-hello/workflows/hello.nf
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
include { paramsSummaryMap       } from 'plugin/nf-schema'
include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline'

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    RUN MAIN WORKFLOW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

workflow HELLO {

    take:
    ch_samplesheet // canal: samplesheet llegit des de --input
    main:

    ch_versions = channel.empty()

    //
    // Collate and save software versions
    //
    def topic_versions = Channel.topic("versions")
        .distinct()
        .branch { entry ->
            versions_file: entry instanceof Path
            versions_tuple: true
        }

    def topic_versions_string = topic_versions.versions_tuple
        .map { process, tool, version ->
            [ process[process.lastIndexOf(':')+1..-1], "  ${tool}: ${version}" ]
        }
        .groupTuple(by:0)
        .map { process, tool_versions ->
            tool_versions.unique().sort()
            "${process}:\n${tool_versions.join('\n')}"
        }

    softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file))
        .mix(topic_versions_string)
        .collectFile(
            storeDir: "${params.outdir}/pipeline_info",
            name:  'hello_software_'  + 'versions.yml',
            sort: true,
            newLine: true
        ).set { ch_collated_versions }


    emit:
    versions       = ch_versions                 // canal: [ path(versions.yml) ]

}

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    THE END
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

En comparació amb un workflow bàsic de Nextflow com el desenvolupat a Hello Nextflow, notareu algunes coses que són noves aquí (línies destacades anteriorment):

  • El bloc workflow té un nom
  • Les entrades del workflow es declaren utilitzant la paraula clau take: i la construcció del canal es mou cap al workflow pare
  • El contingut del workflow es col·loca dins d'un bloc main:
  • Les sortides es declaren utilitzant la paraula clau emit:

Aquestes són funcionalitats opcionals de Nextflow que fan que el workflow sigui composable, és a dir, que es pot cridar des de dins d'un altre workflow.

El bloc Channel.topic

Potser haureu notat el bloc def topic_versions = Channel.topic("versions") que comença a la línia 17. Aquest és codi de manteniment estàndard que recull informació de versions de programari de tots els mòduls automàticament. nf-core està desplegant aquest mecanisme a tots els pipelines el 2026, de manera que el veureu a tots els nous pipelines d'ara endavant. La Part 4 d'aquest curs explica com funciona en detall.

Necessitarem connectar la lògica rellevant del nostre workflow d'interès a aquesta estructura.

Conclusió

Ara sabeu com crear una estructura de pipeline utilitzant les eines nf-core i comparar-la amb l'estructura del pipeline demo.

Què segueix?

Apreneu com fer que un workflow simple sigui composable com a preludi per fer-lo compatible amb nf-core.


3. Fer el workflow Hello Nextflow composable

Ara és el moment de posar-se a treballar integrant el nostre workflow a l'estructura nf-core.

Com a recordatori, estem treballant amb el workflow presentat al nostre curs de formació Hello Nextflow. Aquest workflow es va escriure com un workflow simple sense nom que es pot executar per si sol.

Per tal de tenir clar quines parts del workflow original han d'anar a cada lloc de l'estructura nf-core, començarem transformant el workflow Hello original en un workflow composable que es pugui executar des de dins d'un workflow pare, tal com requereix la plantilla nf-core.

Això és el que estem intentant construir ara:

hello.nfsayHello.nfconvertToUpper.nfcollectGreetings.nfcowpy.nfmain.nfincludeincludemodules/

En essència, volem imitar l'estructura modular de l'estructura nf-core, però amb menys complexitat per començar.

Us proporcionem una còpia neta i totalment funcional del workflow Hello Nextflow completat al directori original-hello juntament amb els seus mòduls i el fitxer CSV per defecte que espera utilitzar com a entrada.

tree original-hello/
Contingut del directori
original-hello/
├── hello.nf
├── modules
│   ├── collectGreetings.nf
│   ├── convertToUpper.nf
│   ├── cowpy.nf
│   └── sayHello.nf
└── nextflow.config

1 directory, 6 files

Sentiu-vos lliures d'executar-lo per assegurar-vos que funciona:

nextflow run original-hello/hello.nf
Sortida de la comanda
N E X T F L O W   ~  version 25.10.4

Launching `original-hello/hello.nf` [goofy_babbage] DSL2 - revision: e9e72441e9

executor >  local (8)
[a4/081cec] sayHello (1)       | 3 of 3 ✔
[e7/7e9058] convertToUpper (3) | 3 of 3 ✔
[0c/17263b] collectGreetings   | 1 of 1 ✔
[94/542280] cowpy              | 1 of 1 ✔

Si funciona, esteu a punt per començar a modificar el codi.

3.1. Modificar el workflow Hello original

Obrim el fitxer de workflow hello.nf per inspeccionar el codi, que es mostra complet a continuació (sense comptar els processos, que estan en mòduls):

original-hello/hello.nf
#!/usr/bin/env nextflow

/*
* Pipeline parameters
*/
params.greeting = 'greetings.csv'
params.batch = 'test-batch'
params.character = 'turkey'

// Include modules
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'
include { collectGreetings } from './modules/collectGreetings.nf'
include { cowpy } from './modules/cowpy.nf'

workflow {

  // crea un canal per a entrades des d'un fitxer CSV
  greeting_ch = channel.fromPath(params.greeting)
                      .splitCsv()
                      .map { line -> line[0] }

  // emet una salutació
  sayHello(greeting_ch)

  // converteix la salutació a majúscules
  convertToUpper(sayHello.out)

  // recull totes les salutacions en un fitxer
  collectGreetings(convertToUpper.out.collect(), params.batch)

  // genera art ASCII de les salutacions amb cowpy
  cowpy(collectGreetings.out.outfile, params.character)
}

Com podeu veure, aquest workflow es va escriure com un workflow simple sense nom que es pot executar per si sol. Per fer-lo composable, farem els canvis següents:

  1. Donar nom al workflow
  2. Substituir la construcció del canal per take:
  3. Prefaciar les operacions del workflow amb main:
  4. Afegir la declaració emit:

Recorrem els canvis necessaris un per un.

3.1.1. Donar nom al workflow

Primer, donem un nom al workflow perquè puguem referir-nos-hi des d'un workflow pare.

original-hello/hello.nf
workflow HELLO {
original-hello/hello.nf
workflow {

Les mateixes convencions s'apliquen als noms de workflow que als noms de mòdul.

3.1.2. Substituir la construcció del canal per take

Ara, substituïu la construcció del canal per una simple declaració take que declara les entrades esperades.

original-hello/hello.nf
    take:
    // canal de salutacions
    greeting_ch
original-hello/hello.nf
    // crea un canal per a entrades des d'un fitxer CSV
    greeting_ch = channel.fromPath(params.greeting)
                        .splitCsv()
                        .map { line -> line[0] }

Això deixa els detalls de com es proporcionen les entrades al workflow pare.

Mentre hi som, també podem comentar la línia params.greeting = 'greetings.csv'

original-hello/hello.nf
3
4
5
6
7
8
    /*
    * Pipeline parameters
    */
    //params.greeting = 'greetings.csv'
    params.batch = 'test-batch'
    params.character = 'turkey'
original-hello/hello.nf
3
4
5
6
7
8
    /*
    * Pipeline parameters
    */
    params.greeting = 'greetings.csv'
    params.batch = 'test-batch'
    params.character = 'turkey'

Nota

Si teniu instal·lada l'extensió del servidor de llenguatge Nextflow, el verificador de sintaxi il·luminarà el vostre codi amb línies ondulades vermelles. Això és perquè si poseu una declaració take:, també heu de tenir un main:.

Ho afegirem al següent pas.

3.1.3. Prefaciar les operacions del workflow amb la declaració main

A continuació, afegiu una declaració main abans de la resta d'operacions cridades al cos del workflow.

original-hello/hello.nf
    main:

    // emet una salutació
    sayHello(greeting_ch)

    // converteix la salutació a majúscules
    convertToUpper(sayHello.out)

    // recull totes les salutacions en un fitxer
    collectGreetings(convertToUpper.out.collect(), params.batch)

    // genera art ASCII de les salutacions amb cowpy
    cowpy(collectGreetings.out.outfile, params.character)
original-hello/hello.nf
    // emet una salutació
    sayHello(greeting_ch)

    // converteix la salutació a majúscules
    convertToUpper(sayHello.out)

    // recull totes les salutacions en un fitxer
    collectGreetings(convertToUpper.out.collect(), params.batch)

    // genera art ASCII de les salutacions amb cowpy
    cowpy(collectGreetings.out.outfile, params.character)

Això bàsicament diu 'això és el que fa aquest workflow'.

3.1.4. Afegir la declaració emit

Finalment, afegiu una declaració emit que declara quines són les sortides finals del workflow.

original-hello/hello.nf
    emit:
    cowpy_hellos = cowpy.out

Aquesta és una addició completament nova al codi en comparació amb el workflow original.

3.1.5. Resum dels canvis completats

Si heu fet tots els canvis tal com es descriuen, el vostre workflow ara hauria de semblar així:

original-hello/hello.nf
#!/usr/bin/env nextflow

/*
* Pipeline parameters
*/
// params.greeting = 'greetings.csv'
params.batch = 'test-batch'
params.character = 'turkey'

// Include modules
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'
include { collectGreetings } from './modules/collectGreetings.nf'
include { cowpy } from './modules/cowpy.nf'

workflow HELLO {

    take:
    // canal de salutacions
    greeting_ch

    main:

    // emet una salutació
    sayHello(greeting_ch)

    // converteix la salutació a majúscules
    convertToUpper(sayHello.out)

    // recull totes les salutacions en un fitxer
    collectGreetings(convertToUpper.out.collect(), params.batch)

    // genera art ASCII de les salutacions amb cowpy
    cowpy(collectGreetings.out.outfile, params.character)

    emit:
    cowpy_hellos = cowpy.out
}

Això descriu tot el que Nextflow necessita EXCEPTE què alimentar al canal d'entrada. Això es definirà al workflow pare, també anomenat workflow entrypoint.

3.2. Fer un workflow entrypoint fictici

Abans d'integrar el nostre workflow composable a l'estructura complexa nf-core, verifiquem que funciona correctament. Podem fer un workflow entrypoint fictici simple per provar el workflow composable de manera aïllada.

Creeu un fitxer en blanc anomenat main.nf al mateix directori original-hello.

touch original-hello/main.nf

Copieu el següent codi al fitxer main.nf.

original-hello/main.nf
#!/usr/bin/env nextflow

// importa el codi del workflow des del fitxer hello.nf
include { HELLO } from './hello.nf'

// declara el paràmetre d'entrada
params.greeting = 'greetings.csv'

workflow {
  // crea un canal per a entrades des d'un fitxer CSV
  greeting_ch = channel.fromPath(params.greeting)
                      .splitCsv()
                      .map { line -> line[0] }

  // crida el workflow importat sobre el canal de salutacions
  HELLO(greeting_ch)

  // visualitza les sortides emeses pel workflow
  HELLO.out.view { output -> "Output: $output" }
}

Hi ha dues observacions importants a fer aquí:

  • La sintaxi per cridar el workflow importat és essencialment la mateixa que la sintaxi per cridar mòduls.
  • Tot el que està relacionat amb portar les entrades al workflow (paràmetre d'entrada i construcció del canal) ara es declara en aquest workflow pare.

Nota

Anomenar el fitxer de workflow entrypoint main.nf és una convenció, no un requisit.

Si seguiu aquesta convenció, podeu ometre especificar el nom del fitxer de workflow a la vostra comanda nextflow run. Nextflow buscarà automàticament un fitxer anomenat main.nf al directori d'execució.

No obstant això, podeu anomenar el fitxer de workflow entrypoint d'una altra manera si ho preferiu. En aquest cas, assegureu-vos d'especificar el nom del fitxer de workflow a la vostra comanda nextflow run.

3.3. Comprovar que el workflow s'executa

Finalment tenim totes les peces que necessitem per verificar que el workflow composable funciona. Executem-lo!

nextflow run ./original-hello

Aquí veieu l'avantatge d'utilitzar la convenció de nomenclatura main.nf. Si haguéssim anomenat el workflow entrypoint something_else.nf, hauríem hagut de fer nextflow run original-hello/something_else.nf.

Si heu fet tots els canvis correctament, això hauria de completar-se.

Sortida de la comanda
N E X T F L O W   ~  version 25.10.4

Launching `original-hello/main.nf` [friendly_wright] DSL2 - revision: 1ecd2d9c0a

executor >  local (8)
[24/c6c0d8] HELLO:sayHello (3)       | 3 of 3 ✔
[dc/721042] HELLO:convertToUpper (3) | 3 of 3 ✔
[48/5ab2df] HELLO:collectGreetings   | 1 of 1 ✔
[e3/693b7e] HELLO:cowpy              | 1 of 1 ✔
Output: /workspaces/training/hello-nf-core/work/e3/693b7e48dc119d0c54543e0634c2e7/cowpy-COLLECTED-test-batch-output.txt

Això significa que hem actualitzat amb èxit el nostre workflow HELLO per ser composable.

Conclusió

Sabeu com fer un workflow composable donant-li un nom i afegint declaracions take, main i emit, i com cridar-lo des d'un workflow entrypoint.

Què segueix?

Apreneu com injertar un workflow composable bàsic a l'estructura nf-core.


4. Ajustar la lògica del workflow actualitzat al workflow de marcador de posició

Ara que hem verificat que el nostre workflow composable funciona correctament, tornem a l'estructura del pipeline nf-core que vam crear a la secció 1. Volem integrar el workflow composable que acabem de desenvolupar a l'estructura de plantilla nf-core, de manera que el resultat final hauria de semblar així.

subworkflows/workflows/hello.nfmain.nfincludeincludemodules/local/local/utils_nfcore_demo_pipeline/main.nfnf-core/utils_*/main.nfsayHello.nfconvertToUpper.nfcollectGreetings.nfcowpy.nf

Així doncs, com ho fem? Donem una ullada al contingut actual del workflow HELLO a core-hello/workflows/hello.nf (l'estructura nf-core).

core-hello/workflows/hello.nf
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
include { paramsSummaryMap       } from 'plugin/nf-schema'
include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline'

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    RUN MAIN WORKFLOW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

workflow HELLO {

    take:
    ch_samplesheet // canal: samplesheet llegit des de --input
    main:

    ch_versions = channel.empty()

    //
    // Collate and save software versions
    //
    def topic_versions = Channel.topic("versions")
        .distinct()
        .branch { entry ->
            versions_file: entry instanceof Path
            versions_tuple: true
        }

    def topic_versions_string = topic_versions.versions_tuple
        .map { process, tool, version ->
            [ process[process.lastIndexOf(':')+1..-1], "  ${tool}: ${version}" ]
        }
        .groupTuple(by:0)
        .map { process, tool_versions ->
            tool_versions.unique().sort()
            "${process}:\n${tool_versions.join('\n')}"
        }

    softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file))
        .mix(topic_versions_string)
        .collectFile(
            storeDir: "${params.outdir}/pipeline_info",
            name:  'hello_software_'  + 'versions.yml',
            sort: true,
            newLine: true
        ).set { ch_collated_versions }


    emit:
    versions       = ch_versions                 // canal: [ path(versions.yml) ]

}

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    THE END
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

Les línies destacades defineixen l'estructura del workflow composable: workflow HELLO {, take:, main: i emit:. El gran bloc entre les línies 17–34 és més substancial: gestiona la captura de versions de programari utilitzant topic channels, un mecanisme que nf-core està desplegant a tots els pipelines el 2026. Ho explicarem a la Part 4; de moment, tracteu-lo com a codi estàndard que podeu deixar sense modificar.

Necessitem afegir el codi rellevant de la versió composable del workflow original que vam desenvolupar a la secció 2.

Abordarem això en les següents etapes:

  1. Copiar els mòduls i configurar les importacions de mòduls
  2. Deixar la declaració take tal com està
  3. Afegir la lògica del workflow al bloc main
  4. Actualitzar el bloc emit

Nota

Ignorarem el bloc de captura de versions per a aquesta primera passada. La Part 4 explica com funciona.

4.1. Copiar els mòduls i configurar les importacions de mòduls

Els quatre processos del nostre workflow Hello Nextflow s'emmagatzemen com a mòduls a original-hello/modules/. Necessitem copiar aquests mòduls a l'estructura del projecte nf-core (sota core-hello/modules/local/) i afegir declaracions d'importació al fitxer de workflow nf-core.

Primer copiem els fitxers de mòdul de original-hello/ a core-hello/:

mkdir -p core-hello/modules/local/
cp original-hello/modules/* core-hello/modules/local/.

Ara hauríeu de veure el directori de mòduls llistat sota core-hello/.

tree core-hello/modules
Contingut del directori
core-hello/modules
└── local
    ├── collectGreetings.nf
    ├── convertToUpper.nf
    ├── cowpy.nf
    └── sayHello.nf

1 directory, 4 files

Ara configurem les declaracions d'importació de mòduls.

Aquestes eren les declaracions d'importació al workflow original-hello/hello.nf:

original-hello/hello.nf
// Include modules
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'
include { collectGreetings } from './modules/collectGreetings.nf'
include { cowpy } from './modules/cowpy.nf'

Obriu el fitxer core-hello/workflows/hello.nf i transposeu aquestes declaracions d'importació tal com es mostra a continuació.

core-hello/workflows/hello.nf
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
include { paramsSummaryMap       } from 'plugin/nf-schema'
include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline'
include { sayHello               } from '../modules/local/sayHello.nf'
include { convertToUpper         } from '../modules/local/convertToUpper.nf'
include { collectGreetings       } from '../modules/local/collectGreetings.nf'
include { cowpy                  } from '../modules/local/cowpy.nf'
core-hello/workflows/hello.nf
1
2
3
4
5
6
7
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
include { paramsSummaryMap       } from 'plugin/nf-schema'
include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline'

Dues observacions més interessants aquí:

  • Hem adaptat el format de les declaracions d'importació per seguir la convenció d'estil nf-core.
  • Hem actualitzat els camins relatius als mòduls per reflectir que ara s'emmagatzemen a un nivell diferent de niament.

4.2. Deixar la declaració take tal com està

El projecte nf-core té molta funcionalitat preconstruïda al voltant del concepte del samplesheet, que normalment és un fitxer CSV que conté dades en columnes. Com que això és essencialment el que és el nostre fitxer greetings.csv, mantindrem la declaració take actual tal com està, i simplement actualitzarem el nom del canal d'entrada al següent pas.

core-hello/workflows/hello.nf
    take:
    ch_samplesheet // canal: samplesheet llegit des de --input

El maneig de l'entrada es farà abans d'aquest workflow (no en aquest fitxer de codi).

4.3. Afegir la lògica del workflow al bloc main

Ara que els nostres mòduls estan disponibles per al workflow, podem connectar la lògica del workflow al bloc main.

Com a recordatori, aquest és el codi rellevant al workflow original, que no va canviar gaire quan el vam fer composable (només vam afegir la línia main:):

original-hello/hello.nf
    main:

    // emet una salutació
    sayHello(greeting_ch)

    // converteix la salutació a majúscules
    convertToUpper(sayHello.out)

    // recull totes les salutacions en un fitxer
    collectGreetings(convertToUpper.out.collect(), params.batch)

    // genera art ASCII de les salutacions amb cowpy
    cowpy(collectGreetings.out.outfile, params.character)

Necessitem copiar el codi que ve després de main: a la nova versió del workflow.

Ja hi ha algun codi allà que té a veure amb capturar les versions de les eines que executa el workflow. Ho deixarem estar per ara (tractarem les versions de les eines més endavant). Mantindrem la inicialització ch_versions = channel.empty() a la part superior, després inserirem la nostra lògica de workflow, mantenint el codi de recopilació de versions al final. Aquest ordre té sentit perquè en un pipeline real, els processos emetrien informació de versió que s'afegiria al canal ch_versions mentre s'executa el workflow.

core-hello/workflows/hello.nf
workflow HELLO {

    take:
    ch_samplesheet // canal: samplesheet llegit des de --input

    main:

    ch_versions = channel.empty()

    // emet una salutació
    sayHello(greeting_ch)

    // converteix la salutació a majúscules
    convertToUpper(sayHello.out)

    // recull totes les salutacions en un fitxer
    collectGreetings(convertToUpper.out.collect(), params.batch)

    // genera art ASCII de les salutacions amb cowpy
    cowpy(collectGreetings.out.outfile, params.character)

    //
    // Collate and save software versions
    //
    def topic_versions = Channel.topic("versions")
        .distinct()
        .branch { entry ->
            versions_file: entry instanceof Path
            versions_tuple: true
        }

    def topic_versions_string = topic_versions.versions_tuple
        .map { process, tool, version ->
            [ process[process.lastIndexOf(':')+1..-1], "  ${tool}: ${version}" ]
        }
        .groupTuple(by:0)
        .map { process, tool_versions ->
            tool_versions.unique().sort()
            "${process}:\n${tool_versions.join('\n')}"
        }

    softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file))
        .mix(topic_versions_string)
        .collectFile(
            storeDir: "${params.outdir}/pipeline_info",
            name:  'hello_software_'  + 'versions.yml',
            sort: true,
            newLine: true
        ).set { ch_collated_versions }


    emit:
    versions       = ch_versions                 // canal: [ path(versions.yml) ]

}
core-hello/workflows/hello.nf
workflow HELLO {

    take:
    ch_samplesheet // canal: samplesheet llegit des de --input
    main:

    ch_versions = channel.empty()

    //
    // Collate and save software versions
    //
    def topic_versions = Channel.topic("versions")
        .distinct()
        .branch { entry ->
            versions_file: entry instanceof Path
            versions_tuple: true
        }

    def topic_versions_string = topic_versions.versions_tuple
        .map { process, tool, version ->
            [ process[process.lastIndexOf(':')+1..-1], "  ${tool}: ${version}" ]
        }
        .groupTuple(by:0)
        .map { process, tool_versions ->
            tool_versions.unique().sort()
            "${process}:\n${tool_versions.join('\n')}"
        }

    softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file))
        .mix(topic_versions_string)
        .collectFile(
            storeDir: "${params.outdir}/pipeline_info",
            name:  'hello_software_'  + 'versions.yml',
            sort: true,
            newLine: true
        ).set { ch_collated_versions }


    emit:
    versions       = ch_versions                 // canal: [ path(versions.yml) ]

}

Notareu que també hem afegit una línia en blanc abans de main: per fer el codi més llegible.

Això es veu genial, però encara necessitem actualitzar el nom del canal que estem passant al procés sayHello() de greeting_ch a ch_samplesheet tal com es mostra a continuació, per coincidir amb el que està escrit sota la paraula clau take:.

core-hello/workflows/hello.nf
    // emet una salutació (actualitzat per utilitzar la convenció nf-core per a samplesheets)
    sayHello(ch_samplesheet)
core-hello/workflows/hello.nf
    // emet una salutació
    sayHello(greeting_ch)

Ara la lògica del workflow està correctament connectada.

4.4. Actualitzar el bloc emit

Finalment, necessitem actualitzar el bloc emit per incloure la declaració de les sortides finals del workflow.

core-hello/workflows/hello.nf
    emit:
    cowpy_hellos   = cowpy.out
    versions       = ch_versions                 // canal: [ path(versions.yml) ]
core-hello/workflows/hello.nf
    emit:
    versions       = ch_versions                 // canal: [ path(versions.yml) ]

Això conclou les modificacions que necessitem fer al workflow HELLO en si. En aquest punt, hem aconseguit l'estructura general del codi que ens vam proposar implementar.

Conclusió

Sabeu com ajustar les peces centrals d'un workflow composable a un workflow de marcador de posició nf-core.

Què segueix?

Apreneu com adaptar com es gestionen les entrades a l'estructura del pipeline nf-core.


5. Adaptar el maneig d'entrades

Ara que hem integrat amb èxit la nostra lògica de workflow a l'estructura nf-core, necessitem abordar una peça més crítica: assegurar-nos que les nostres dades d'entrada es processen correctament. La plantilla nf-core ve amb un maneig d'entrades sofisticat dissenyat per a conjunts de dades genòmiques complexes, així que necessitem adaptar-lo per treballar amb el nostre fitxer greetings.csv més simple.

5.1. Identificar on es gestionen les entrades

El primer pas és esbrinar on es fa el maneig d'entrades.

Potser recordeu que quan vam reescriure el workflow Hello Nextflow per ser composable, vam moure la declaració del paràmetre d'entrada un nivell cap amunt, al workflow entrypoint main.nf. Així doncs, donem una ullada al workflow entrypoint main.nf de nivell superior que es va crear com a part de l'estructura del pipeline:

core-hello/main.nf
#!/usr/bin/env nextflow
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    core/hello
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Github : https://github.com/core/hello
----------------------------------------------------------------------------------------
*/

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

include { HELLO  } from './workflows/hello'
include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_hello_pipeline'
include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hello_pipeline'
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    NAMED WORKFLOWS FOR PIPELINE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

//
// WORKFLOW: Run main analysis pipeline depending on type of input
//
workflow CORE_HELLO {

    take:
    samplesheet // canal: samplesheet llegit des de --input

    main:

    //
    // WORKFLOW: Run pipeline
    //
    HELLO (
        samplesheet
    )
}
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    RUN MAIN WORKFLOW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

workflow {

    main:
    //
    // SUBWORKFLOW: Run initialisation tasks
    //
    PIPELINE_INITIALISATION (
        params.version,
        params.validate_params,
        params.monochrome_logs,
        args,
        params.outdir,
        params.input,
        params.help,
        params.help_full,
        params.show_hidden
    )

    //
    // WORKFLOW: Run main workflow
    //
    CORE_HELLO (
        PIPELINE_INITIALISATION.out.samplesheet
    )
    //
    // SUBWORKFLOW: Run completion tasks
    //
    PIPELINE_COMPLETION (
        params.outdir,
        params.monochrome_logs,
    )
}

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    THE END
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

El projecte nf-core fa un ús intensiu de subworkflows niats, així que aquesta part pot ser una mica confusa a la primera aproximació.

El que importa aquí és que hi ha dos workflows definits:

  • CORE_HELLO és un embolcall prim per executar el workflow HELLO que acabem d'acabar d'adaptar a core-hello/workflows/hello.nf.
  • Un workflow sense nom que crida CORE_HELLO així com dos altres subworkflows, PIPELINE_INITIALISATION i PIPELINE_COMPLETION.

Aquí hi ha un diagrama de com es relacionen entre ells:

PIPELINE_INITIALISATIONPIPELINE_COMPLETIONCORE_HELLO { HELLO}samplesheetdata filesoutput filespipeline reportsunnamed workflow in main.nf

Importantment, no podem trobar cap codi que construeixi un canal d'entrada a aquest nivell, només referències a un samplesheet proporcionat mitjançant el paràmetre --input.

Una mica d'investigació revela que el maneig d'entrades es fa pel subworkflow PIPELINE_INITIALISATION, apropiadament, que s'importa de core-hello/subworkflows/local/utils_nfcore_hello_pipeline/main.nf.

Si obrim aquest fitxer i desplacem cap avall, arribem a aquest fragment de codi:

core-hello/subworkflows/local/utils_nfcore_hello_pipeline/main.nf
    //
    // Create channel from input file provided through params.input
    //

    channel
        .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json"))
        .map {
            meta, fastq_1, fastq_2 ->
                if (!fastq_2) {
                    return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ]
                } else {
                    return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ]
                }
        }
        .groupTuple()
        .map { samplesheet ->
            validateInputSamplesheet(samplesheet)
        }
        .map {
            meta, fastqs ->
                return [ meta, fastqs.flatten() ]
        }
        .set { ch_samplesheet }

    emit:
    samplesheet = ch_samplesheet
    versions    = ch_versions

Aquesta és la factoria de canals que analitza el samplesheet i el passa en una forma que està llesta per ser consumida pel workflow HELLO.

Nota

La sintaxi anterior és una mica diferent del que hem utilitzat anteriorment, però bàsicament això:

channel.<...>.set { ch_samplesheet }

és equivalent a això:

ch_samplesheet = channel.<...>

Aquest codi implica alguns passos d'anàlisi i validació que són altament específics del samplesheet d'exemple inclòs amb la plantilla del pipeline nf-core, que en el moment d'escriure això és molt específic del domini i no és adequat per al nostre projecte de pipeline simple.

5.2. Substituir el codi del canal d'entrada de la plantilla

La bona notícia és que les necessitats del nostre pipeline són molt més simples, així que podem substituir tot això pel codi de construcció de canal que vam desenvolupar al workflow original Hello Nextflow.

Com a recordatori, així és com es veia la construcció del canal (tal com es veu al directori de solucions):

solutions/composable-hello/main.nf
    // crea un canal per a entrades des d'un fitxer CSV
    greeting_ch = channel.fromPath(params.greeting)
        .splitCsv()
        .map { line -> line[0] }

Així que només necessitem connectar això al workflow d'inicialització, amb canvis menors: actualitzem el nom del canal de greeting_ch a ch_samplesheet, i el nom del paràmetre de params.greeting a params.input (vegeu la línia destacada).

core-hello/subworkflows/local/utils_nfcore_hello_pipeline/main.nf
    //
    // Create channel from input file provided through params.input
    //

    ch_samplesheet = channel.fromPath(params.input)
        .splitCsv()
        .map { line -> line[0] }

    emit:
    samplesheet = ch_samplesheet
    versions    = ch_versions
core-hello/subworkflows/local/utils_nfcore_hello_pipeline/main.nf
    //
    // Create channel from input file provided through params.input
    //

    channel
        .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json"))
        .map {
            meta, fastq_1, fastq_2 ->
                if (!fastq_2) {
                    return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ]
                } else {
                    return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ]
                }
        }
        .groupTuple()
        .map { samplesheet ->
            validateInputSamplesheet(samplesheet)
        }
        .map {
            meta, fastqs ->
                return [ meta, fastqs.flatten() ]
        }
        .set { ch_samplesheet }

    emit:
    samplesheet = ch_samplesheet
    versions    = ch_versions

Això completa els canvis que necessitem per fer que el processament d'entrades funcioni.

En la seva forma actual, això no ens permetrà aprofitar les capacitats integrades d'nf-core per a la validació d'esquemes, però podem afegir-ho més endavant. Per ara, ens centrem en mantenir-ho tan simple com sigui possible per arribar a alguna cosa que puguem executar amb èxit amb dades de prova.

5.3. Actualitzar el perfil de test

Parlant de dades de prova i paràmetres, actualitzem el perfil de test per a aquest pipeline per utilitzar el mini-samplesheet greetings.csv en lloc del samplesheet d'exemple proporcionat a la plantilla.

Sota core-hello/conf, trobem dos perfils de test de plantilla: test.config i test_full.config, que estan destinats a provar una mostra de dades petita i una de mida completa. Donat el propòsit del nostre pipeline, realment no té sentit configurar un perfil de test de mida completa, així que sentiu-vos lliures d'ignorar o eliminar test_full.config. Ens centrarem en configurar test.config per executar-se al nostre fitxer greetings.csv amb alguns paràmetres per defecte.

5.3.1. Copiar el fitxer greetings.csv

Primer necessitem copiar el fitxer greetings.csv a un lloc apropiat al nostre projecte de pipeline. Normalment els fitxers de prova petits s'emmagatzemen al directori assets, així que copiem el fitxer des del nostre directori de treball.

cp greetings.csv core-hello/assets/.

Ara el fitxer greetings.csv està llest per ser utilitzat com a entrada de prova.

5.3.2. Actualitzar el fitxer test.config

Ara podem actualitzar el fitxer test.config de la següent manera:

core-hello/conf/test.config
params {
    config_profile_name        = 'Test profile'
    config_profile_description = 'Minimal test dataset to check pipeline function'

    // Input data
    input  = "${projectDir}/assets/greetings.csv"

    // Other parameters
    batch     = 'test'
    character = 'tux'
}
core-hello/conf/test.config
params {
    config_profile_name        = 'Test profile'
    config_profile_description = 'Minimal test dataset to check pipeline function'

    // Input data
    // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets
    // TODO nf-core: Give any required params for the test so that command line flags are not needed
    input  = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv'
}

Punts clau:

  • Utilitzant ${projectDir}: Aquesta és una variable implícita de Nextflow que apunta al directori on es troba l'script de workflow principal (l'arrel del pipeline). Utilitzar-la assegura que el camí funcioni independentment d'on s'executi el pipeline.
  • Camins absoluts: Utilitzant ${projectDir}, creem un camí absolut, que és important per a dades de prova que s'envien amb el pipeline.
  • Ubicació de dades de prova: Els pipelines nf-core normalment emmagatzemen dades de prova al directori assets/ dins del repositori del pipeline per a fitxers de prova petits, o fan referència a conjunts de dades de prova externs per a fitxers més grans.

I mentre hi som, ajustem els límits de recursos per defecte per assegurar que això s'executarà en màquines molt bàsiques (com les VMs mínimes a Github Codespaces):

core-hello/conf/test.config
process {
    resourceLimits = [
        cpus: 2,
        memory: '4.GB',
        time: '1.h'
    ]
}
core-hello/conf/test.config
process {
    resourceLimits = [
        cpus: 4,
        memory: '15.GB',
        time: '1.h'
    ]
}

Això completa les modificacions de codi que necessitem fer.

5.4. Executar el pipeline amb el perfil de test

Ha estat molt, però finalment podem provar d'executar el pipeline! Tingueu en compte que hem d'afegir --validate_params false a la línia de comandes perquè encara no hem configurat la validació (això vindrà més endavant).

nextflow run core-hello --outdir core-hello-results -profile test,docker --validate_params false

Si heu fet totes les modificacions correctament, hauria de completar-se.

Sortida de la comanda
 N E X T F L O W   ~  version 25.10.4

Launching `core-hello/main.nf` [condescending_allen] DSL2 - revision: b9e9b3b8de

Input/output options
  input                     : /workspaces/training/hello-nf-core/core-hello/assets/greetings.csv
  outdir                    : core-hello-results

Institutional config options
  config_profile_name       : Test profile
  config_profile_description: Minimal test dataset to check pipeline function

Generic options
  validate_params           : false
  trace_report_suffix       : 2025-11-21_07-29-37

Core Nextflow options
  runName                   : condescending_allen
  containerEngine           : docker
  launchDir                 : /workspaces/training/hello-nf-core
  workDir                   : /workspaces/training/hello-nf-core/work
  projectDir                : /workspaces/training/hello-nf-core/core-hello
  userName                  : root
  profile                   : test,docker
  configFiles               : /workspaces/training/hello-nf-core/core-hello/nextflow.config

!! Only displaying parameters that differ from the pipeline defaults !!
------------------------------------------------------
executor >  local (1)
[ed/727b7e] CORE_HELLO:HELLO:sayHello (3)       [100%] 3 of 3 ✔
[45/bb6096] CORE_HELLO:HELLO:convertToUpper (3) [100%] 3 of 3 ✔
[81/7e2e34] CORE_HELLO:HELLO:collectGreetings   [100%] 1 of 1 ✔
[96/9442a1] CORE_HELLO:HELLO:cowpy              [100%] 1 of 1 ✔
-[core/hello] Pipeline completed successfully-

Com podeu veure, això va produir el resum típic d'nf-core a l'inici gràcies al subworkflow d'inicialització, i les línies per a cada mòdul ara mostren els noms complets PIPELINE:WORKFLOW:module.

5.5. Trobar les sortides del pipeline

La pregunta ara és: on són les sortides del pipeline? I la resposta és força interessant: ara hi ha dos llocs diferents per buscar els resultats.

Com potser recordeu d'abans, la nostra primera execució del workflow recentment creat va produir un directori anomenat core-hello-results/ que contenia diversos informes d'execució i metadades.

tree core-hello-results
Contingut del directori
core-hello-results
└── pipeline_info
    ├── execution_report_2025-11-21_04-47-18.html
    ├── execution_report_2025-11-21_07-29-37.html
    ├── execution_timeline_2025-11-21_04-47-18.html
    ├── execution_timeline_2025-11-21_07-29-37.html
    ├── execution_trace_2025-11-21_04-47-18.txt
    ├── execution_trace_2025-11-21_07-29-37.txt
    ├── hello_software_versions.yml
    ├── params_2025-11-21_04-47-13.json
    ├── params_2025-11-21_07-29-41.json
    ├── pipeline_dag_2025-11-21_04-47-18.html
    └── pipeline_dag_2025-11-21_07-29-37.html

1 directory, 12 files

Veieu que vam obtenir un altre conjunt d'informes d'execució a més dels que vam obtenir de la primera execució, quan el workflow encara era només un marcador de posició. Aquesta vegada veieu totes les tasques que es van executar com s'esperava.

informe de línia de temps d'execució per al pipeline Hello

Nota

Una vegada més les tasques no es van executar en paral·lel perquè estem executant en una màquina minimalista a Github Codespaces. Per veure-les executar-se en paral·lel, proveu d'augmentar l'assignació de CPU del vostre codespace i els límits de recursos a la configuració de test.

Això és genial, però els nostres resultats reals del pipeline no hi són!

Això és el que va passar: no vam canviar res als mòduls en si, així que les sortides gestionades per les directives publishDir a nivell de mòdul encara van a un directori results tal com s'especifica al pipeline original.

tree results
Contingut del directori
results
├── Bonjour-output.txt
├── COLLECTED-test-batch-output.txt
├── COLLECTED-test-output.txt
├── cowpy-COLLECTED-test-batch-output.txt
├── cowpy-COLLECTED-test-output.txt
├── Hello-output.txt
├── Hola-output.txt
├── UPPER-Bonjour-output.txt
├── UPPER-Hello-output.txt
└── UPPER-Hola-output.txt

0 directories, 10 files

Ah, aquí estan, barrejats amb les sortides d'execucions anteriors del pipeline Hello original.

Si volem que estiguin organitzats de manera ordenada com ho estaven les sortides del pipeline demo, haurem de canviar com configurem les sortides per ser publicades. Us mostrarem com fer-ho més endavant en aquest curs de formació.

I aquí està! Pot semblar molta feina per aconseguir el mateix resultat que el pipeline original, però obteniu tots aquests informes encantadors generats automàticament, i ara teniu una base sòlida per aprofitar funcionalitats addicionals d'nf-core, incloent validació d'entrades i algunes capacitats de maneig de metadades interessants que cobrirem en una secció posterior.


Conclusió

Sabeu com convertir un pipeline Nextflow regular en un pipeline d'estil nf-core utilitzant la plantilla nf-core. Com a part d'això, heu après com fer un workflow composable, i com identificar els elements de la plantilla nf-core que més comunament necessiten ser adaptats quan es desenvolupa un pipeline d'estil nf-core personalitzat.

Què segueix?

Feu una pausa, ha estat una feina dura! Quan estigueu preparats, passeu a Part 3: Use an nf-core module per aprendre com aprofitar mòduls mantinguts per la comunitat del repositori nf-core/modules.