diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 06d0f54..d1e1062 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -64,7 +64,7 @@ jobs: runs-on: # use self-hosted runners - runs-on=${{ github.run_id }}-nf-test - runner=4cpu-linux-x64 - - disk=large + - volume=80gb strategy: fail-fast: false matrix: diff --git a/bin/spatialdata_merge.py b/bin/spatialdata_merge.py index 409d8c0..5359a7b 100755 --- a/bin/spatialdata_merge.py +++ b/bin/spatialdata_merge.py @@ -6,8 +6,6 @@ import os import shutil -import spatialdata - def parse_args(): """Parse command-line arguments.""" diff --git a/bin/spatialdata_meta.py b/bin/spatialdata_meta.py index 935f39b..20a9c0e 100755 --- a/bin/spatialdata_meta.py +++ b/bin/spatialdata_meta.py @@ -7,7 +7,6 @@ import pandas as pd import spatialdata as sd -import zarr # Fix zarr v3 + anndata + numcodecs incompatibility: # anndata's string writer passes numcodecs.VLenUTF8 to zarr.Group.create_array, diff --git a/bin/spatialdata_write.py b/bin/spatialdata_write.py index 421e830..3a4723e 100755 --- a/bin/spatialdata_write.py +++ b/bin/spatialdata_write.py @@ -5,7 +5,6 @@ import sys import pandas as pd -import spatialdata from spatialdata_io import xenium # Fix zarr v3 + anndata + numcodecs incompatibility: diff --git a/conf/modules.config b/conf/modules.config index c94e0d2..845f0df 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -20,10 +20,6 @@ process { // ---------------------------- multiqc --------------------------------------------------- - withName: 'MULTIQC|MULTIQC_PRE_XR_RUN|MULTIQC_POST_XR_RUN' { - errorStrategy = 'ignore' - } - withName: MULTIQC { ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } publishDir = [ @@ -72,6 +68,13 @@ process { path: "${params.outdir}/${params.mode}/xeniumranger/resegment", mode: params.publish_dir_mode, ] + ext.args = {[ + // Disable boundary/interior stain when the param is falsy; keep tool default when truthy. + !params.boundary_stain ? "--boundary-stain=disable" : "", + !params.interior_stain ? "--interior-stain=disable" : "", + params.expansion_distance != null ? "--expansion-distance=${params.expansion_distance}" : "", + params.dapi_filter != null ? "--dapi-filter=${params.dapi_filter}" : "", + ].join(' ').trim()} } withName: XENIUMRANGER_IMPORT_SEGMENTATION { @@ -79,6 +82,9 @@ process { path: "${params.outdir}/${params.mode}/xeniumranger/import_segementation", mode: params.publish_dir_mode, ] + ext.args = {[ + params.expansion_distance != null ? "--expansion-distance=${params.expansion_distance}" : "", + ].join(' ').trim()} } // ---------------------------- proseg --------------------------------------------------- @@ -88,7 +94,9 @@ process { path: "${params.outdir}/${params.mode}/proseg/preset", mode: params.publish_dir_mode, ] - ext.format = { params.format ?: 'xenium' } + ext.args = {[ + params.format != null ? "--${params.format}" : "", + ].join(' ').trim()} } withName: PROSEG2BAYSOR { @@ -173,8 +181,11 @@ process { path: { "${params.outdir}/${params.mode}/segger/create_dataset" }, mode: params.publish_dir_mode, ] - ext.args = { "--tile-width ${params.tile_width} --tile-height ${params.tile_height}" } - ext.format = { params.format ?: 'xenium' } + ext.args = {[ + params.format != null ? "--sample-type ${params.format}" : "", + params.tile_width != null ? "--tile-width ${params.tile_width}" : "", + params.tile_height != null ? "--tile-height ${params.tile_height}" : "", + ].join(' ').trim()} } withName: SEGGER_TRAIN { @@ -182,10 +193,12 @@ process { path: { "${params.outdir}/${params.mode}/segger/train" }, mode: params.publish_dir_mode, ] - ext.devices = params.devices - ext.args = { "--batch_size ${params.batch_size_train} --max_epochs ${params.max_epochs} --num_workers ${params.segger_num_workers}" } - ext.args2 = { "--init_emb 8 --hidden_channels 32 --num_tx_tokens 10000 --out_channels 8 --heads 2 --num_mid_layers 2 --strategy auto --precision bf16-mixed" } - maxForks = params.restrict_concurrency ? 1 : 0 + ext.args = {[ + "--init_emb 8 --hidden_channels 32 --num_tx_tokens 10000 --out_channels 8 --heads 2 --num_mid_layers 2 --strategy auto --precision bf16-mixed", + params.batch_size_train != null ? "--batch_size ${params.batch_size_train}" : "", + params.max_epochs != null ? "--max_epochs ${params.max_epochs}" : "", + params.segger_num_workers != null ? "--num_workers ${params.segger_num_workers}" : "", + ].join(' ').trim()} } withName: SEGGER_PREDICT { @@ -195,7 +208,11 @@ process { // Skip partitioned parquet dirs (Hive-style) that S3 copy can't handle saveAs: { filename -> filename.contains('transcripts_df.parquet') ? null : filename }, ] - ext.args = { "--batch-size ${params.batch_size_predict} --cc-analysis ${params.cc_analysis} --knn-method ${params.segger_knn_method}" } + ext.args = {[ + params.batch_size_predict != null ? "--batch-size ${params.batch_size_predict}" : "", + params.cc_analysis != null ? "--cc-analysis ${params.cc_analysis}" : "", + params.segger_knn_method != null ? "--knn-method ${params.segger_knn_method}" : "", + ].join(' ').trim()} } // ---------------------------- ficture ------------------------------------------ diff --git a/main.nf b/main.nf index 14193a1..b6dde5f 100644 --- a/main.nf +++ b/main.nf @@ -105,6 +105,7 @@ workflow { params.help, params.help_full, params.show_hidden, + params.format, params.gene_panel, params.gene_synonyms, params.image_seg_methods, diff --git a/modules.json b/modules.json index 38be276..17d34a4 100644 --- a/modules.json +++ b/modules.json @@ -56,8 +56,7 @@ "xeniumranger/import-segmentation": { "branch": "master", "git_sha": "39365e944e936511e33b993cdd978e0f12adac9a", - "installed_by": ["modules"], - "patch": "modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff" + "installed_by": ["modules"] }, "xeniumranger/relabel": { "branch": "master", @@ -67,8 +66,7 @@ "xeniumranger/resegment": { "branch": "master", "git_sha": "39365e944e936511e33b993cdd978e0f12adac9a", - "installed_by": ["modules"], - "patch": "modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff" + "installed_by": ["modules"] } } }, diff --git a/modules/local/proseg/preset/main.nf b/modules/local/proseg/preset/main.nf index f700e27..553801b 100644 --- a/modules/local/proseg/preset/main.nf +++ b/modules/local/proseg/preset/main.nf @@ -23,18 +23,12 @@ process PROSEG { def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" - def format = task.ext.format ?: 'xenium' - - // check for platform values - if (!(format in ['xenium', 'cosmx', 'merscope'])) { - error("${format} is an invalid platform type. Please specify xenium, cosmx, or merscope") - } """ mkdir -p ${prefix} proseg \\ - --${format} \\ + ${args} \\ ${transcripts} \\ --nthreads ${task.cpus} \\ --output-expected-counts ${prefix}/expected-counts.csv.gz \\ @@ -45,8 +39,7 @@ process PROSEG { --output-cell-polygons ${prefix}/cell-polygons.geojson.gz \\ --output-cell-polygon-layers ${prefix}/cell-polygons-layers.geojson.gz \\ --output-union-cell-polygons ${prefix}/union-cell-polygons.geojson.gz \\ - --output-spatialdata ${prefix}/proseg-output.zarr \\ - ${args} + --output-spatialdata ${prefix}/proseg-output.zarr """ stub: diff --git a/modules/local/segger/create_dataset/main.nf b/modules/local/segger/create_dataset/main.nf index ded29b0..d7a31c1 100644 --- a/modules/local/segger/create_dataset/main.nf +++ b/modules/local/segger/create_dataset/main.nf @@ -1,7 +1,6 @@ process SEGGER_CREATE_DATASET { tag "${meta.id}" label 'process_xl' - maxForks params.restrict_concurrency ? 1 : 0 container "quay.io/dongzehe/segger:1.0.14" @@ -23,12 +22,6 @@ process SEGGER_CREATE_DATASET { def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" - def format = task.ext.format ?: 'xenium' - - // check for platform values - if (!(format in ['xenium'])) { - error("${format} is an invalid platform type.") - } """ export NUMBA_CACHE_DIR=\$PWD/.numba_cache @@ -37,7 +30,6 @@ process SEGGER_CREATE_DATASET { segger_create_dataset.py \\ --bundle-dir ${base_dir} \\ --output-dir ${prefix} \\ - --sample-type ${format} \\ --n-workers ${task.cpus} \\ ${args} """ diff --git a/modules/local/segger/train/main.nf b/modules/local/segger/train/main.nf index 7e94b21..c441d18 100644 --- a/modules/local/segger/train/main.nf +++ b/modules/local/segger/train/main.nf @@ -22,14 +22,11 @@ process SEGGER_TRAIN { } def args = task.ext.args ?: '' - def args2 = task.ext.args2 ?: '' def script_path = "/workspace/segger_dev/src/segger/cli/train_model.py" prefix = task.ext.prefix ?: "${meta.id}" - // Scale GPU count with retries: 4 → 8 (capped at params.devices) def gpu_count = 2 * task.attempt def cuda_visible = gpu_count == 1 ? "export CUDA_VISIBLE_DEVICES=0" : "" def accelerator = task.accelerator ? 'gpu' : 'auto' - def num_devices = task.devices ?: 0 """ # Set numba cache directory to avoid caching issues in container @@ -38,7 +35,7 @@ process SEGGER_TRAIN { # GPU detection logging echo "=== GPU Detection (SEGGER_TRAIN) ===" - echo "Requested devices: ${gpu_count} (attempt ${task.attempt}, max ${num_devices})" + echo "Requested devices: ${gpu_count} (attempt ${task.attempt})" echo "Accelerator: ${accelerator}" nvidia-smi 2>/dev/null && echo "GPU available: yes" || echo "GPU available: no (nvidia-smi failed)" python3 -c "import torch; print(f'PyTorch CUDA available: {torch.cuda.is_available()}'); print(f'CUDA device count: {torch.cuda.device_count()}')" 2>/dev/null || echo "PyTorch CUDA check failed" @@ -51,8 +48,7 @@ process SEGGER_TRAIN { --sample_tag ${prefix} \\ --devices ${gpu_count} \\ --accelerator ${accelerator} \\ - ${args} \\ - ${args2} + ${args} """ stub: diff --git a/modules/local/spatialdata/merge/main.nf b/modules/local/spatialdata/merge/main.nf index 46f13cc..db61400 100644 --- a/modules/local/spatialdata/merge/main.nf +++ b/modules/local/spatialdata/merge/main.nf @@ -12,7 +12,7 @@ process SPATIALDATA_MERGE { output: tuple val(meta), path("spatialdata/${prefix}/${outputfolder}"), emit: merged_bundle - tuple val("${task.process}"), val('spatialdata'), eval('python3 -c "import spatialdata; print(spatialdata.__version__)"'), topic: versions, emit: versions_spatialdata + tuple val("${task.process}"), val('spatialdata'), eval("pip show spatialdata | sed -n 's/^Version: //p'"), topic: versions, emit: versions_spatialdata when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/meta/main.nf b/modules/local/spatialdata/meta/main.nf index 73925a3..714bf79 100644 --- a/modules/local/spatialdata/meta/main.nf +++ b/modules/local/spatialdata/meta/main.nf @@ -12,7 +12,7 @@ process SPATIALDATA_META { output: tuple val(meta), path("spatialdata/${prefix}/${outputfolder}"), emit: metadata - tuple val("${task.process}"), val('spatialdata'), eval('python3 -c "import spatialdata; print(spatialdata.__version__)"'), topic: versions, emit: versions_spatialdata + tuple val("${task.process}"), val('spatialdata'), eval("pip show spatialdata | sed -n 's/^Version: //p'"), topic: versions, emit: versions_spatialdata when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/write/main.nf b/modules/local/spatialdata/write/main.nf index b7b2c20..6caed6c 100644 --- a/modules/local/spatialdata/write/main.nf +++ b/modules/local/spatialdata/write/main.nf @@ -14,7 +14,7 @@ process SPATIALDATA_WRITE { output: tuple val(meta), path("spatialdata/${prefix}/${outputfolder}"), emit: spatialdata - tuple val("${task.process}"), val('spatialdata'), eval('python3 -c "import spatialdata; print(spatialdata.__version__)"'), topic: versions, emit: versions_spatialdata + tuple val("${task.process}"), val('spatialdata'), eval("pip show spatialdata | sed -n 's/^Version: //p'"), topic: versions, emit: versions_spatialdata when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/downscale_morphology/main.nf b/modules/local/utility/downscale_morphology/main.nf index ab4f478..ef5143e 100644 --- a/modules/local/utility/downscale_morphology/main.nf +++ b/modules/local/utility/downscale_morphology/main.nf @@ -30,8 +30,8 @@ process DOWNSCALE_MORPHOLOGY { tuple val(meta), path("${prefix}/downscaled.tif"), emit: downscaled tuple val(meta), path("${prefix}/scale_info.json"), emit: scale_info tuple val("${task.process}"), val('python'), eval("python3 --version | sed 's/Python //'"), topic: versions, emit: versions_python - tuple val("${task.process}"), val('tifffile'), eval('python3 -c "import tifffile; print(tifffile.__version__)"'), topic: versions, emit: versions_tifffile - tuple val("${task.process}"), val('scikit-image'), eval('python3 -c "import skimage; print(skimage.__version__)"'), topic: versions, emit: versions_skimage + tuple val("${task.process}"), val('tifffile'), eval("pip show tifffile 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_tifffile + tuple val("${task.process}"), val('scikit-image'), eval("pip show scikit-image 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_skimage when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/parquet_to_csv/main.nf b/modules/local/utility/parquet_to_csv/main.nf index 9c31fe4..865408b 100644 --- a/modules/local/utility/parquet_to_csv/main.nf +++ b/modules/local/utility/parquet_to_csv/main.nf @@ -12,7 +12,7 @@ process PARQUET_TO_CSV { output: tuple val(meta), path("${prefix}/*.csv*"), emit: transcripts_csv - tuple val("${task.process}"), val('pyarrow'), eval('python3 -c "import pyarrow; print(pyarrow.__version__)"'), topic: versions, emit: versions_pyarrow + tuple val("${task.process}"), val('pyarrow'), eval("pip show pyarrow 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_pyarrow when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/resize_tif/main.nf b/modules/local/utility/resize_tif/main.nf index 35685b7..00fe213 100644 --- a/modules/local/utility/resize_tif/main.nf +++ b/modules/local/utility/resize_tif/main.nf @@ -12,7 +12,7 @@ process RESIZE_TIF { output: tuple val(meta), path("${meta.id}/resized_*.tif"), emit: resized_mask tuple val("${task.process}"), val('python'), eval("python3 --version | sed 's/Python //'"), topic: versions, emit: versions_python - tuple val("${task.process}"), val('tifffile'), eval('python3 -c "import tifffile; print(tifffile.__version__)"'), topic: versions, emit: versions_tifffile + tuple val("${task.process}"), val('tifffile'), eval("pip show tifffile 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_tifffile when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/upscale_mask/main.nf b/modules/local/utility/upscale_mask/main.nf index 246290f..2fc896e 100644 --- a/modules/local/utility/upscale_mask/main.nf +++ b/modules/local/utility/upscale_mask/main.nf @@ -27,7 +27,7 @@ process UPSCALE_MASK { output: tuple val(meta), path("${prefix}/upscaled_*.tif"), emit: upscaled_mask tuple val("${task.process}"), val('python'), eval("python3 --version | sed 's/Python //'"), topic: versions, emit: versions_python - tuple val("${task.process}"), val('tifffile'), eval('python3 -c "import tifffile; print(tifffile.__version__)"'), topic: versions, emit: versions_tifffile + tuple val("${task.process}"), val('tifffile'), eval("pip show tifffile 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_tifffile when: task.ext.when == null || task.ext.when diff --git a/modules/local/xenium_patch/divide/main.nf b/modules/local/xenium_patch/divide/main.nf index 5032417..957b162 100644 --- a/modules/local/xenium_patch/divide/main.nf +++ b/modules/local/xenium_patch/divide/main.nf @@ -26,7 +26,7 @@ process XENIUM_PATCH_DIVIDE { tuple val(meta), path("patches/patch_grid.json") , emit: grid tuple val(meta), path("patches/patch_*/transcripts.parquet") , emit: patch_transcripts tuple val("${task.process}"), val('python'), eval("python3 --version | sed 's/Python //'"), topic: versions, emit: versions_python - tuple val("${task.process}"), val('pyarrow'), eval('python3 -c "import pyarrow; print(pyarrow.__version__)"'), topic: versions, emit: versions_pyarrow + tuple val("${task.process}"), val('pyarrow'), eval("pip show pyarrow 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_pyarrow when: task.ext.when == null || task.ext.when diff --git a/modules/local/xenium_patch/stitch/main.nf b/modules/local/xenium_patch/stitch/main.nf index c674a40..83d7fed 100644 --- a/modules/local/xenium_patch/stitch/main.nf +++ b/modules/local/xenium_patch/stitch/main.nf @@ -27,7 +27,7 @@ process XENIUM_PATCH_STITCH { path("output/xr-cell-polygons.geojson"), path("output/xr-transcript-metadata.csv") , emit: xr_polygons_transcript tuple val("${task.process}"), val('python'), eval("python3 --version | sed 's/Python //'"), topic: versions, emit: versions_python - tuple val("${task.process}"), val('sopa'), eval('python3 -c "import sopa; print(sopa.__version__)"'), topic: versions, emit: versions_sopa + tuple val("${task.process}"), val('sopa'), eval("pip show sopa 2>/dev/null | sed -n 's/^Version: //p'"), topic: versions, emit: versions_sopa when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/import-segmentation/main.nf index 4931053..264b8a7 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/import-segmentation/main.nf @@ -36,7 +36,6 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { if (cells) { assembled_args << "--cells=\"${cells}\"" } if (transcript_assignment) { assembled_args << "--transcript-assignment=\"${transcript_assignment}\"" } if (viz_polygons) { assembled_args << "--viz-polygons=\"${viz_polygons}\"" } - if (nuclei) { assembled_args << "--expansion-distance=${params.expansion_distance}" } if (coordinate_transform) { assembled_args << "--coordinate-transform=\"${coordinate_transform}\"" // if coordinate_transform is provided, units must be microns diff --git a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff deleted file mode 100644 index ea2652a..0000000 --- a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff +++ /dev/null @@ -1,14 +0,0 @@ -Changes in component 'nf-core/xeniumranger/import-segmentation' -'modules/nf-core/xeniumranger/import-segmentation/meta.yml' is unchanged -Changes in 'xeniumranger/import-segmentation/main.nf': ---- modules/nf-core/xeniumranger/import-segmentation/main.nf -+++ modules/nf-core/xeniumranger/import-segmentation/main.nf -@@ -36,6 +36,7 @@ - if (cells) { assembled_args << "--cells=\"${cells}\"" } - if (transcript_assignment) { assembled_args << "--transcript-assignment=\"${transcript_assignment}\"" } - if (viz_polygons) { assembled_args << "--viz-polygons=\"${viz_polygons}\"" } -+ if (nuclei) { assembled_args << "--expansion-distance=${params.expansion_distance}" } - if (coordinate_transform) { - assembled_args << "--coordinate-transform=\"${coordinate_transform}\"" - // if coordinate_transform is provided, units must be microns -************************************************************ diff --git a/modules/nf-core/xeniumranger/resegment/main.nf b/modules/nf-core/xeniumranger/resegment/main.nf index df2b0ea..d52eba0 100644 --- a/modules/nf-core/xeniumranger/resegment/main.nf +++ b/modules/nf-core/xeniumranger/resegment/main.nf @@ -24,19 +24,10 @@ process XENIUMRANGER_RESEGMENT { prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: "" - // Do not use boundary stain in analysis, but keep default interior stain and DAPI - def boundary_stain = params.boundary_stain ? "" : "--boundary-stain=disable" - // Do not use interior stain in analysis, but keep default boundary stain and DAPI - def interior_stain = params.interior_stain ? "" : "--interior-stain=disable" - """ xeniumranger resegment \\ --id="XENIUMRANGER_RESEGMENT" \\ --xenium-bundle="${xenium_bundle}" \\ - --expansion-distance=${params.expansion_distance} \\ - --dapi-filter=${params.dapi_filter} \\ - ${boundary_stain} \\ - ${interior_stain} \\ --localcores=${task.cpus} \\ --localmem=${task.memory.toGiga()} \\ ${args} diff --git a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff deleted file mode 100644 index afa09c2..0000000 --- a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff +++ /dev/null @@ -1,30 +0,0 @@ -Changes in component 'nf-core/xeniumranger/resegment' -'modules/nf-core/xeniumranger/resegment/meta.yml' is unchanged -Changes in 'xeniumranger/resegment/main.nf': ---- modules/nf-core/xeniumranger/resegment/main.nf -+++ modules/nf-core/xeniumranger/resegment/main.nf -@@ -24,10 +24,24 @@ - prefix = task.ext.prefix ?: "${meta.id}" - def args = task.ext.args ?: "" - -+ // Do not use boundary stain in analysis, but keep default interior stain and DAPI -+ def boundary_stain = params.boundary_stain ? "" : "--boundary-stain=disable" -+ // Do not use interior stain in analysis, but keep default boundary stain and DAPI -+ def interior_stain = params.interior_stain ? "" : "--interior-stain=disable" -+ - """ - xeniumranger resegment \\ - --id="XENIUMRANGER_RESEGMENT" \\ - --xenium-bundle="${xenium_bundle}" \\ -+ --expansion-distance=${params.expansion_distance} \\ -+ --dapi-filter=${params.dapi_filter} \\ -+ ${boundary_stain} \\ -+ ${interior_stain} \\ - --localcores=${task.cpus} \\ - --localmem=${task.memory.toGiga()} \\ - ${args} -'modules/nf-core/xeniumranger/resegment/tests/main.nf.test.snap' is unchanged -'modules/nf-core/xeniumranger/resegment/tests/tags.yml' is unchanged -'modules/nf-core/xeniumranger/resegment/tests/nextflow.config' is unchanged -'modules/nf-core/xeniumranger/resegment/tests/main.nf.test' is unchanged -************************************************************ diff --git a/nextflow.config b/nextflow.config index 73be717..214a5b6 100644 --- a/nextflow.config +++ b/nextflow.config @@ -127,7 +127,6 @@ params { // pipeline dev and testing option buffer_samples = false // process one sample at a time from the multi-sample samplesheet buffer_size = 1 // buffer size 0 means no buffering of samples - restrict_concurrency = false // restrict running certain process in parallel // Boilerplate options publish_dir_mode = 'copy' @@ -275,13 +274,13 @@ profiles { // Must repeat base.config label properties — profile withLabel replaces, not merges ext.use_gpu = { params.use_gpu } accelerator = { params.use_gpu ? 1 : null } - containerOptions = { "--shm-size ${task.memory.toGiga().intValue()}g" } + containerOptions = { "--shm-size ${task.memory.toGiga()}g" } queue = { params.gpu_queue ?: null } } withLabel:process_gpu_single { ext.use_gpu = { params.use_gpu } accelerator = { params.use_gpu ? 1 : null } - containerOptions = { "--shm-size ${task.memory.toGiga().intValue()}g" } + containerOptions = { "--shm-size ${task.memory.toGiga()}g" } queue = { params.cellpose_queue ?: params.gpu_queue ?: null } } } diff --git a/nextflow_schema.json b/nextflow_schema.json index 0c47e33..3817956 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -219,7 +219,8 @@ "format": { "type": "string", "default": "xenium", - "description": "Preset value for the proseg segmentation method." + "enum": ["xenium", "cosmx", "merscope"], + "description": "Input data platform. Used by proseg, segger, and spatialdata modules." }, "image_seg_methods": { "type": "array", @@ -418,11 +419,6 @@ "type": "integer", "description": "Number of sample(s) to process at a time from a multi-sample samplesheet. Works if buffered_samples is true.", "default": 1 - }, - "restrict_concurrency": { - "type": "boolean", - "description": "Restrict parallelizing a process. Eg. restrict running cellpose cell and nuclei segmentation together if the resources are limited.", - "default": false } } }, diff --git a/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf b/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf index 0f37c17..334133d 100644 --- a/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf @@ -34,6 +34,7 @@ workflow PIPELINE_INITIALISATION { help // boolean: Display help message and exit help_full // boolean: Show the full help message show_hidden // boolean: Show hidden parameters in the help message + format // string: input data platform (xenium | cosmx | merscope) gene_panel // string: path to gene panel gene_synonyms // string: path to gene synonyms image_seg_methods // list: valid image-mode segmentation methods @@ -107,6 +108,7 @@ workflow PIPELINE_INITIALISATION { input, mode, method, + format, image_seg_methods, transcript_seg_methods, relabel_genes, @@ -209,6 +211,7 @@ def validateInputParameters( input, mode, method, + format, image_seg_methods, transcript_seg_methods, relabel_genes, @@ -244,6 +247,16 @@ def validateInputParameters( } } + // check method-format compatibility (schema enum constrains the universe; this enforces the method-specific subset) + def valid_segger_formats = ['xenium'] + def valid_proseg_formats = ['xenium', 'cosmx', 'merscope'] + if (method == 'segger' && !(format in valid_segger_formats)) { + error("❌ Error: Invalid --format '${format}' for segger. Valid: ${valid_segger_formats}") + } + if (method == 'proseg' && !(format in valid_proseg_formats)) { + error("❌ Error: Invalid --format '${format}' for proseg. Valid: ${valid_proseg_formats}") + } + // check if --relabel_genes is true but --gene_panel is not provided if (relabel_genes && !gene_panel) { log.warn("⚠️ Relabel genes is enabled, but gene panel is not provided with the `--gene_panel`. Using `gene_panel.json` in the xenium bundle.")