From 29083dbd8b9d0da026d01ac32290c092d0fb8f70 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Wed, 28 Oct 2026 21:03:01 +0100 Subject: [PATCH] Reject --align-chain up front where seed chaining cannot work Seed chaining needs seed coordinates, which the labeled aligner has only with an annotation with coordinates on a BASIC-mode graph (the annotation buffer disables coordinates on CANONICAL and PRIMARY graphs). Otherwise, align_both_directions logged "Skipping seed chaining" and then called exit(1) from a worker thread, so align printed nothing for any read. align_to_graph now checks these requirements after loading the graph and the annotation and fails with an error saying what --align-chain needs. The message in the aligner no longer claims to skip chaining. Co-Authored-By: Claude Opus 5.5 --- metagraph/integration_tests/test_align.py | 37 +++++++++++++++++++ metagraph/src/cli/align.cpp | 13 +++++++ metagraph/src/graph/alignment/dbg_aligner.cpp | 2 +- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/metagraph/integration_tests/test_align.py b/metagraph/integration_tests/test_align.py index 4261ff4be5..1070b5cfd1 100644 --- a/metagraph/integration_tests/test_align.py +++ b/metagraph/integration_tests/test_align.py @@ -391,6 +391,43 @@ def test_simple_align_edit_distance_all_graphs(self, representation): self.assertEqual(a, b) + def test_align_chain_requires_coordinates(self): + def build(mode): + graph = self.tempdir.name + f'/genome.MT.{mode}' + self._build_graph(input=TEST_DATA_DIR + '/genome.MT.fa', + output=graph, k=11, repr='succinct', mode=mode) + return graph + '.dbg' + + def annotate(graph, anno_repr): + prefix = graph[:-len('.dbg')] + self._annotate_graph(TEST_DATA_DIR + '/genome.MT.fa', graph, prefix, anno_repr) + return f'{prefix}.{anno_repr}.annodbg' + + def align(graph, anno): + command = f'{METAGRAPH} align --align-chain -i {graph} -a {anno} '\ + f'{TEST_DATA_DIR}/genome_MT1.fq' + return subprocess.run(command.split(), stdout=PIPE, stderr=PIPE) + + basic = build('basic') + canonical = build('canonical') + + # no coordinates in the annotation + res = align(basic, annotate(basic, 'column')) + self.assertNotEqual(res.returncode, 0) + self.assertIn('--align-chain requires', res.stderr.decode()) + self.assertEqual(res.stdout, b'') + + # coordinates are not used on CANONICAL graphs + res = align(canonical, annotate(canonical, 'column_coord')) + self.assertNotEqual(res.returncode, 0) + self.assertIn('--align-chain requires', res.stderr.decode()) + + # a BASIC graph with coordinates is accepted + res = align(basic, annotate(basic, 'column_coord')) + self.assertEqual(res.returncode, 0) + self.assertEqual(len(res.stdout.decode().rstrip().split('\n')), 7) + + @unittest.skipUnless(PROTEIN_MODE, "These alignment tests are only for the Protein alphabet") class TestProteinAlign(TestingBase): def setUp(self): diff --git a/metagraph/src/cli/align.cpp b/metagraph/src/cli/align.cpp index 3e25af0564..7f8ed5e1ad 100644 --- a/metagraph/src/cli/align.cpp +++ b/metagraph/src/cli/align.cpp @@ -10,6 +10,7 @@ #include "graph/alignment/dbg_aligner.hpp" #include "graph/alignment/aligner_labeled.hpp" #include "graph/annotated_dbg.hpp" +#include "annotation/int_matrix/base/int_matrix.hpp" #include "graph/graph_extensions/node_first_cache.hpp" #include "seq_io/sequence_io.hpp" #include "config/config.hpp" @@ -382,6 +383,18 @@ int align_to_graph(Config *config) { if (anno_dbg_future.valid()) anno_dbg = anno_dbg_future.get(); + // Chaining needs the coordinates of the seeds, which the aligner uses only + // with an annotation with coordinates on a BASIC-mode graph. + if (config->alignment_chain + && (graph->get_mode() != DeBruijnGraph::BASIC || !anno_dbg + || !dynamic_cast( + &anno_dbg->get_annotator().get_matrix()))) { + logger->error("--align-chain requires a BASIC-mode graph and an annotation " + "with coordinates (e.g., annotate --coordinates, then " + "transform_anno --anno-type column_coord)"); + return 1; + } + auto wrap_graph = [&](auto graph) { if (graph->get_mode() == DeBruijnGraph::PRIMARY) { graph = std::make_shared(graph); diff --git a/metagraph/src/graph/alignment/dbg_aligner.cpp b/metagraph/src/graph/alignment/dbg_aligner.cpp index 40ca019612..b7a6e693e9 100644 --- a/metagraph/src/graph/alignment/dbg_aligner.cpp +++ b/metagraph/src/graph/alignment/dbg_aligner.cpp @@ -545,7 +545,7 @@ ::align_both_directions(std::string_view forward, if (config_.chain_alignments) { if (!has_coordinates()) { - logger->error("Chaining only supported for seeds with coordinates. Skipping seed chaining."); + logger->error("Chaining requires seeds with coordinates"); exit(1); }