Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions modules/nf-core/spikeinterface/sort/environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
channels:
- conda-forge
- bioconda
dependencies:
- conda-forge::spikeinterface=0.101.2
69 changes: 69 additions & 0 deletions modules/nf-core/spikeinterface/sort/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
process SPIKEINTERFACE_SORT {
tag "$meta.id"
label 'process_high'

conda "${moduleDir}/environment.yml"
container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ?
'https://depot.galaxyproject.org/singularity/spikeinterface:0.101.2--pyh0610db2_0' :
'biocontainers/spikeinterface:0.101.2--pyh0610db2_0' }"

input:
tuple val(meta), path(recording)
val sorter

output:
tuple val(meta), path("${prefix}/sorting"), emit: sorting
tuple val(meta), path("${prefix}/sorting/spike_times.npy"), emit: spike_times
tuple val(meta), path("${prefix}/sorting/spike_clusters.npy"), emit: spike_clusters
path "versions.yml", emit: versions

when:
task.ext.when == null || task.ext.when

script:
prefix = task.ext.prefix ?: "${meta.id}"
"""
mkdir -p ${prefix}

python - <<'PY'
import os, numpy as np
import spikeinterface.extractors as se
import spikeinterface.sorters as ss

recording = se.read_binary_folder("${recording}") if os.path.isdir("${recording}") \\
else se.read_binary("${recording}", sampling_frequency=30000.0,
dtype="int16", num_channels=1)

sorting = ss.run_sorter(
sorter_name="${sorter}",
recording=recording,
folder="${prefix}/sorting",
remove_existing_folder=True,
)

spikes = sorting.get_all_spike_trains()[0]
np.save("${prefix}/sorting/spike_times.npy", spikes[0])
np.save("${prefix}/sorting/spike_clusters.npy", spikes[1])
PY

cat <<-END_VERSIONS > versions.yml
"${task.process}":
spikeinterface: 0.101.2
spike_sorter: ${sorter}
END_VERSIONS
"""

stub:
prefix = task.ext.prefix ?: "${meta.id}"
"""
mkdir -p ${prefix}/sorting
touch ${prefix}/sorting/spike_times.npy
touch ${prefix}/sorting/spike_clusters.npy

cat <<-END_VERSIONS > versions.yml
"${task.process}":
spikeinterface: 0.101.2
spike_sorter: ${sorter}
END_VERSIONS
"""
}
76 changes: 76 additions & 0 deletions modules/nf-core/spikeinterface/sort/meta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: "spikeinterface_sort"
description: Run spike sorting on extracellular electrophysiology recordings using SpikeInterface
keywords:
- electrophysiology
- spike-sorting
- neuroscience
- neuromorphic
- machine-learning
tools:
- "spikeinterface":
description: "A unified Python framework for spike sorting and electrophysiology analysis"
homepage: "https://spikeinterface.readthedocs.io"
documentation: "https://spikeinterface.readthedocs.io"
tool_dev_url: "https://github.com/SpikeInterface/spikeinterface"
doi: "10.7554/eLife.61834"
licence: ["MIT"]
identifier: "biotools:spikeinterface"

input:
- - meta:
type: map
description: |
Groovy Map containing sample metadata. Required key: `id`.
- recording:
type: file
description: "Input recording readable by SpikeInterface (Neo, NWB, OpenEphys, SpikeGLX, raw binary)."
pattern: "*.{nwb,bin,h5,dat}"
ontologies:
- edam: "http://edamontology.org/data_2603"
- sorter:
type: string
description: "Spike sorter backend identifier. Examples: mountainsort5, kilosort4, herdingspikes, tridesclous."

output:
sorting:
- - meta:
type: map
description: "Groovy Map containing sample metadata."
- "${prefix}/sorting":
type: directory
description: "Sorted units output folder produced by the chosen sorter."
pattern: "*/sorting"
ontologies:
- edam: "http://edamontology.org/data_3494"
spike_times:
- - meta:
type: map
description: "Groovy Map containing sample metadata."
- "${prefix}/sorting/spike_times.npy":
type: file
description: "Spike times as a NumPy array."
pattern: "*.npy"
ontologies:
- edam: "http://edamontology.org/format_3727"
spike_clusters:
- - meta:
type: map
description: "Groovy Map containing sample metadata."
- "${prefix}/sorting/spike_clusters.npy":
type: file
description: "Cluster assignments per spike as a NumPy array."
pattern: "*.npy"
ontologies:
- edam: "http://edamontology.org/format_3727"
versions:
- versions.yml:
type: file
description: "File containing software versions."
pattern: "versions.yml"
ontologies:
- edam: "http://edamontology.org/format_3750"

authors:
- "@olaflaitinen"
maintainers:
- "@olaflaitinen"
62 changes: 62 additions & 0 deletions modules/nf-core/spikeinterface/sort/tests/main.nf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
nextflow_process {

name "Test Process SPIKEINTERFACE_SORT"
script "../main.nf"
process "SPIKEINTERFACE_SORT"

tag "modules"
tag "modules_nfcore"
tag "spikeinterface"
tag "spikeinterface/sort"

test("electrophysiology - small binary recording - mountainsort5") {

when {
process {
"""
input[0] = [
[ id:'test' ],
file(params.modules_testdata_base_path + 'genomics/electrophysiology/recording_small.bin', checkIfExists: true)
]
input[1] = 'mountainsort5'
"""
}
}

then {
assertAll(
{ assert process.success },
{ assert path(process.out.spike_times.get(0).get(1)).exists() },
{ assert snapshot(
process.out.spike_times,
process.out.spike_clusters,
process.out.versions
).match() }
)
}
}

test("electrophysiology - small binary recording - mountainsort5 - stub") {

options "-stub"

when {
process {
"""
input[0] = [
[ id:'test' ],
file(params.modules_testdata_base_path + 'genomics/electrophysiology/recording_small.bin', checkIfExists: true)
]
input[1] = 'mountainsort5'
"""
}
}

then {
assertAll(
{ assert process.success },
{ assert snapshot(process.out).match() }
)
}
}
}
101 changes: 101 additions & 0 deletions modules/nf-core/spikeinterface/sort/tests/main.nf.test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"electrophysiology - small binary recording - mountainsort5": {
"content": [
[
[
{
"id": "test"
},
"spike_times.npy:md5,00000000000000000000000000000001"
]
],
[
[
{
"id": "test"
},
"spike_clusters.npy:md5,00000000000000000000000000000001"
]
],
[
"versions.yml:md5,65e0565a5db2727e46eaf6d361d20d85"
]
],
"meta": {
"nf-test": "0.9.3",
"nextflow": "25.04.8"
},
"timestamp": "1970-01-01T00:00:00"
},
"electrophysiology - small binary recording - mountainsort5 - stub": {
"content": [
{
"0": [
[
{
"id": "test"
},
[
"spike_clusters.npy:md5,d41d8cd98f00b204e9800998ecf8427e",
"spike_times.npy:md5,d41d8cd98f00b204e9800998ecf8427e"
]
]
],
"1": [
[
{
"id": "test"
},
"spike_times.npy:md5,d41d8cd98f00b204e9800998ecf8427e"
]
],
"2": [
[
{
"id": "test"
},
"spike_clusters.npy:md5,d41d8cd98f00b204e9800998ecf8427e"
]
],
"3": [
"versions.yml:md5,65e0565a5db2727e46eaf6d361d20d85"
],
"sorting": [
[
{
"id": "test"
},
[
"spike_clusters.npy:md5,d41d8cd98f00b204e9800998ecf8427e",
"spike_times.npy:md5,d41d8cd98f00b204e9800998ecf8427e"
]
]
],
"spike_clusters": [
[
{
"id": "test"
},
"spike_clusters.npy:md5,d41d8cd98f00b204e9800998ecf8427e"
]
],
"spike_times": [
[
{
"id": "test"
},
"spike_times.npy:md5,d41d8cd98f00b204e9800998ecf8427e"
]
],
"versions": [
"versions.yml:md5,65e0565a5db2727e46eaf6d361d20d85"
]
}
],
"meta": {
"nf-test": "0.9.3",
"nextflow": "25.04.8"
},
"timestamp": "1970-01-01T00:00:00"
}
}
Loading