Skip to content
Open
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
20 changes: 20 additions & 0 deletions tools/mumemto/.shed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
description: Mumemto - efficient maximal matching across pangenomes
categories:
- Sequence Analysis
owner: bgruening
homepage_url: https://github.com/vikshiv/mumemto
long_description: |
Mumemto is a tool for finding maximal unique matches (multi-MUMs) and
maximal exact matches (multi-MEMs) across pangenomes using prefix-free
parsing (PFP). It includes subcommands for visualization, coverage
analysis, collinear block detection, format conversion, sequence
extraction, BED conversion, partition merging, and inversion detection.
remote_repository_url: https://github.com/bgruening/galaxytools/tree/master/tools/mumemto
type: unrestricted
auto_tool_repositories:
name_template: "{{ tool_id }}"
description_template: "Wrapper for mumemto application {{ tool_name }}."
suite:
name: "suite_mumemto"
description: "A suite of Galaxy tools for the mumemto pangenome matching toolkit"
type: repository_suite_definition
47 changes: 47 additions & 0 deletions tools/mumemto/macros.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<macros>
<token name="@TOOL_VERSION@">1.4.1</token>
<token name="@VERSION_SUFFIX@">0</token>
<token name="@PROFILE@">25.0</token>
<xml name="requirements">
<requirements>
<requirement type="package" version="@TOOL_VERSION@">mumemto</requirement>
</requirements>
</xml>
<xml name="version_command">
<!-- this can be replaces by mumento --version 2>&1 once version 1.4.2 is released -->
<version_command><![CDATA[echo "mumemto @TOOL_VERSION@"]]></version_command>
</xml>
<xml name="citations">
<citations>
<citation type="doi">10.1186/s13059-025-03644-0</citation>
</citations>
</xml>
<!-- Reusable MUMs file input -->
<xml name="input_mums">
<param argument="-m" type="data" format="txt" label="MUMs file" help="Output .mums file from mumemto. Binary .bumbl files must be converted with mumemto convert first"/>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure users know what those mms and bumbl files are.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the output files generated by mumento_convert. We can more info in the help desc

</xml>
<!-- Reusable lengths file input -->
<xml name="input_lengths">
<param argument="-l" type="data" format="txt" label="Lengths file" help="Output .lengths file from mumemto"/>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which mumento outputs those?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes from mumento output

<data name="lengths_output" format="txt" from_work_dir="output.lengths" label="${tool.name} lengths on ${on_string}"/>

</xml>
<!-- Shared configfile for the -f (filelist) flag. The param itself is inlined
in each tool because -f does different things: viz reorders sequences,
inversion relabels them 1:1 by position. -->
<xml name="configfile_filelist">
<configfiles>
<configfile name="filelist_file">$filelist_text</configfile>
</configfiles>
</xml>
<!-- Reusable length filter param -->
<xml name="param_length_filter">
<param argument="-L" type="integer" value="0" min="0" label="Length filter" help="Only consider MUMs of at least this length"/>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe set to 1

</xml>
<!-- Reusable max gap param -->
<xml name="param_max_gap">
<param argument="-g" type="integer" value="1000" min="0" label="Maximum gap length" help="Maximum allowed gap between collinear MUMs"/>
</xml>
<!-- Contig spacer, shared by the multi-FASTA layout modes of mumemto viz -->
<xml name="param_spacer">
<param argument="--spacer" type="float" value="0.1" min="0" max="1" label="Contig spacer" help="Gap drawn between contigs, as a fraction of the longest contig's length"/>
</xml>
</macros>
297 changes: 297 additions & 0 deletions tools/mumemto/mumemto.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
<tool id="mumemto" name="mumemto" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="@PROFILE@">
<description>compute multi-MUMs and multi-MEMs across pangenomes</description>
<macros>
<import>macros.xml</import>
</macros>
<expand macro="requirements"/>
<expand macro="version_command"/>
<command detect_errors="aggressive"><![CDATA[
#import re
## The file list is built here rather than taken from the user: mumemto resolves the
## paths inside it, and any path a user could supply would point outside the job.
## names.tsv maps the path mumemto will record to the dataset name, see the awk below.
#for $i, $fasta in enumerate($input_fasta):
ln -s '$fasta' 'seq_${i}.fa' &&
echo 'seq_${i}.fa' >> filelist.txt &&
printf '%s\t%s\n' "\$(readlink -f 'seq_${i}.fa')" '${re.sub("[^\w.-]", "_", str($fasta.element_identifier))}' >> names.tsv &&
#end for

mumemto
-i filelist.txt
-o 'output'
-l $l
#if str($k):
-k $k
#end if
#if str($F):
-F $F
#end if
$no_revcomp
#if str($matches.match_type) == "mum":
## -f 1 is what makes a match unique, i.e. a MUM rather than a MEM
-f 1
$matches.b
#if str($matches.merge.mode) != "none":
-M
#if str($matches.merge.mode) == "anchor":
-n
#end if
#end if
#else:
-f $matches.f
#end if
-w $advanced.w
-m $advanced.m
$advanced.g
$advanced.K
&&

## mumemto records each input's canonicalised path in the .lengths file, which resolves
## the symlinks above to opaque Galaxy dataset paths. Substitute the dataset names back:
## the rest of the suite reads this column for sequence labels, and mumemto merge matches
## partitions by the basename on its first line.
awk 'NR == FNR { name[\$1] = \$2; next } \$1 in name { \$1 = name[\$1] } { print }' names.tsv output.lengths > relabelled.lengths &&
mv relabelled.lengths output.lengths
]]></command>
<inputs>
<param name="input_fasta" type="data" format="fasta,fasta.gz" multiple="true" min="2" label="Input FASTA files" help="Two or more genome sequences, one dataset per genome or haplotype. Their order here becomes the column order in the output."/>
<param argument="-l" type="integer" value="20" min="1" label="Minimum match length" help="Minimum length of a match to report"/>
<param argument="-k" type="integer" optional="true" label="Minimum genomes" help="Minimum number of sequences a match must appear in. Negative values are relative to the number of sequences, so -1 means all but one. Leave empty to require every sequence."/>
<param argument="-F" type="integer" optional="true" label="Maximum total frequency" help="Maximum total occurrences across all sequences. Negative values are relative to the number of sequences. Leave empty for no limit."/>
<param argument="--no-revcomp" type="boolean" truevalue="-r" falsevalue="" checked="false" label="Exclude reverse complement matches" help="By default matches on the reverse strand are included"/>
<conditional name="matches">
<param name="match_type" type="select" label="Match type" help="Unique matches are the usual starting point for pangenome analysis; the rest of the suite is built around them.">
<option value="mum" selected="true">Multi-MUMs - each match occurs at most once per sequence</option>
<option value="mem">Multi-MEMs - a match may repeat within a sequence</option>
</param>
<when value="mum">
<param argument="-b" type="boolean" truevalue="-b" falsevalue="" checked="false" label="Write the binary BUMbl format instead of text" help="Replaces the text .mums output with a compact binary .bumbl file that downstream tools load faster. You do not get both."/>
<conditional name="merge">
<param name="mode" type="select" label="Also write metadata for merging partitions" help="Needed only if this run is one partition of a larger collection that will later be combined with the mumemto merge tool.">
<option value="none" selected="true">No</option>
<option value="anchor">Yes, for anchor-based merging</option>
<option value="string">Yes, for string-based merging</option>
</param>
<when value="none"/>
<when value="anchor"/>
<when value="string"/>
</conditional>
</when>
<when value="mem">
<param argument="-f" type="integer" value="0" min="0" label="Maximum occurrences per sequence" help="0 for no limit. Any value other than 1 produces multi-MEMs; a value of 1 is rejected here because it makes mumemto write a .mums file instead, which is the Multi-MUMs match type above.">
<validator type="expression" message="A value of 1 produces MUMs, not MEMs. Switch match type to Multi-MUMs instead.">value != 1</validator>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet!

</param>
</when>
</conditional>
<section name="advanced" title="Advanced options" expanded="false">
<param argument="-w" type="integer" value="10" min="1" label="PFP window size" help="Prefix-free parsing window size."/>
<param argument="-m" type="integer" value="100" min="1" label="PFP hash modulus" help="Prefix-free parsing hash modulus."/>
<param argument="-g" type="boolean" truevalue="-g" falsevalue="" label="Use gsacak directly" help="Use gsacak instead of the built-in suffix array construction."/>
<param argument="-K" type="boolean" truevalue="-K" falsevalue="" label="Keep temporary files" help="Retain PFP intermediate files for debugging."/>
</section>
</inputs>
<outputs>
<data name="lengths_output" format="txt" from_work_dir="output.lengths" label="${tool.name} lengths on ${on_string}"/>
<!-- mumemto writes .mums only for unique matches, and swaps it for .bumbl when the
binary format is requested, so this is not an unconditional output. -->
<data name="mums_output" format="txt" from_work_dir="output.mums" label="${tool.name} MUMs on ${on_string}">
<filter>matches['match_type'] == 'mum' and not matches['b']</filter>
</data>
<data name="bumbl_output" format="binary" from_work_dir="output.bumbl" label="${tool.name} BUMbl on ${on_string}">
<filter>matches['match_type'] == 'mum' and matches['b']</filter>
</data>
<!-- Any -f other than 1 makes mumemto write .mems instead, with an extra column -->
<data name="mems_output" format="txt" from_work_dir="output.mems" label="${tool.name} MEMs on ${on_string}">
<filter>matches['match_type'] == 'mem'</filter>
</data>
<data name="thresh_output" format="binary" from_work_dir="output.thresh" label="${tool.name} thresholds on ${on_string}">
<filter>matches['match_type'] == 'mum' and matches['merge']['mode'] == 'string'</filter>
</data>
<data name="thresh_rev_output" format="binary" from_work_dir="output.thresh_rev" label="${tool.name} reverse thresholds on ${on_string}">
<filter>matches['match_type'] == 'mum' and matches['merge']['mode'] == 'string'</filter>
</data>
<!-- Anchor mode replaces the two .thresh files with a single .athresh -->
<data name="athresh_output" format="binary" from_work_dir="output.athresh" label="${tool.name} anchor thresholds on ${on_string}">
<filter>matches['match_type'] == 'mum' and matches['merge']['mode'] == 'anchor'</filter>
</data>
</outputs>
<tests>
<!-- Strict multi-MUMs: seq1 and seq2 share one 200 bp block -->
<test expect_num_outputs="2">
<param name="input_fasta" value="seq1.fa,seq2.fa" ftype="fasta"/>
<param name="l" value="10"/>
<output name="mums_output" ftype="txt">
<assert_contents>
<has_n_lines n="1"/>
<has_line line="200&#9;40,50&#9;+,+"/>
</assert_contents>
</output>
<!-- The record names and totals come from the FASTA itself, so they are stable.
No "/" anywhere proves the dataset paths mumemto writes were relabelled. -->
<output name="lengths_output" ftype="txt">
<assert_contents>
<has_n_lines n="4"/>
Comment thread
SaimMomin12 marked this conversation as resolved.
<has_line_matching expression="^\S+ \* 240$"/>
<has_line_matching expression="^\S+ seq1 240$"/>
<has_line_matching expression="^\S+ seq2 299$"/>
<not_has_text text="/"/>
</assert_contents>
</output>
</test>
<!-- Multi-MEMs: a fourth column of sequence indices appears, and the reverse
strand copy of the same block shows up as a second match -->
<test expect_num_outputs="2">
<param name="input_fasta" value="seq1.fa,seq2.fa" ftype="fasta"/>
<param name="l" value="200"/>
<conditional name="matches">
<param name="match_type" value="mem"/>
<param name="f" value="0"/>
</conditional>
<output name="mems_output" ftype="txt">
<assert_contents>
<has_n_lines n="2"/>
<has_line line="200&#9;40,50&#9;0,1&#9;+,+"/>
<has_line line="200&#9;50,41&#9;1,0&#9;-,-"/>
</assert_contents>
</output>
<output name="lengths_output" ftype="txt">
<assert_contents>
<has_n_lines n="4"/>
</assert_contents>
</output>
</test>
<!-- Binary output replaces the text MUMs file, so only two outputs appear -->
<test expect_num_outputs="2">
<param name="input_fasta" value="seq1.fa,seq2.fa" ftype="fasta"/>
<param name="l" value="10"/>
<conditional name="matches">
<param name="match_type" value="mum"/>
<param name="b" value="true"/>
</conditional>
<output name="bumbl_output" ftype="binary">
<assert_contents>
<has_size size="39"/>
</assert_contents>
</output>
<output name="lengths_output" ftype="txt">
<assert_contents>
<has_n_lines n="4"/>
</assert_contents>
</output>
</test>
<!-- String-based merge metadata: two threshold files alongside the MUMs -->
<test expect_num_outputs="4">
<param name="input_fasta" value="seq1.fa,seq2.fa" ftype="fasta"/>
<param name="l" value="10"/>
<conditional name="matches">
<param name="match_type" value="mum"/>
<conditional name="merge">
<param name="mode" value="string"/>
</conditional>
</conditional>
<output name="mums_output" ftype="txt">
<assert_contents>
<has_n_lines n="1"/>
<has_line line="200&#9;40,50&#9;+,+"/>
</assert_contents>
</output>
<output name="lengths_output" ftype="txt">
<assert_contents>
<has_n_lines n="4"/>
</assert_contents>
</output>
<output name="thresh_output" ftype="binary">
<assert_contents>
<has_size size="402"/>
</assert_contents>
</output>
<output name="thresh_rev_output" ftype="binary">
<assert_contents>
<has_size size="402"/>
</assert_contents>
</output>
</test>
<!-- Anchor-based merge metadata: a single .athresh instead of the two above,
which is what the mumemto merge tool consumes -->
<test expect_num_outputs="3">
<param name="input_fasta" value="seq1.fa,seq2.fa" ftype="fasta"/>
<param name="l" value="10"/>
<conditional name="matches">
<param name="match_type" value="mum"/>
<conditional name="merge">
<param name="mode" value="anchor"/>
</conditional>
</conditional>
<output name="mums_output" ftype="txt">
<assert_contents>
<has_n_lines n="1"/>
<has_line line="200&#9;40,50&#9;+,+"/>
</assert_contents>
</output>
<output name="lengths_output" ftype="txt">
<assert_contents>
<has_n_lines n="4"/>
</assert_contents>
</output>
<output name="athresh_output" ftype="binary">
<assert_contents>
<has_size size="482"/>
</assert_contents>
</output>
</test>
</tests>
<help format="markdown"><![CDATA[
**What it does**

Mumemto finds maximal unique matches (multi-MUMs) and maximal exact matches
(multi-MEMs) across a collection of genome sequences (a pangenome). A MUM is a
substring that appears exactly once in every input sequence; a MEM relaxes that
to allow repeats within a sequence. Mumemto uses prefix-free parsing (PFP) for
efficient computation on large genomes.

By default it computes strict multi-MUMs: matches that appear exactly once in
every input sequence. Two settings relax that requirement:

- **Minimum genomes:** accept matches present in only some of the sequences.
Negative values count back from the total, so -1 means all but one.
- **Match type:** switching to multi-MEMs lets a match repeat within a sequence.

-----

**Input**

Two or more FASTA datasets, one per genome or haplotype. The order you select
them in is the order of the coordinate columns in the output, and the first one
becomes the anchor for anchor-based merging.

-----

**Output**

Always a `.lengths` file recording each input file and the length of every record
in it. Downstream tools in this suite need it alongside the matches.

Then, depending on the settings, exactly one file of matches:

- **`.mums`** — tab separated: match length, then one start position per sequence,
then one strand per sequence
- **`.bumbl`** — the same information packed into binary, chosen instead of `.mums`
rather than in addition to it
- **`.mems`** — written when the match type is multi-MEMs. It carries an extra
column between the positions and the strands giving the sequence each position
belongs to, because a match may occur several times in one sequence.

Requesting merge metadata adds either `.thresh` and `.thresh_rev` (string-based)
or a single `.athresh` (anchor-based). Only anchor-based output can be combined
by the *mumemto merge* tool.

-----

**Downstream tools**

The rest of the suite consumes the `.mums` and `.lengths` pair: synteny plots,
coverage, collinear blocks, inversions, BED conversion, MUM sequence extraction,
format conversion and partition merging.
]]></help>
<expand macro="citations"/>
</tool>
Loading
Loading