Files

1271 lines
24 KiB
HTML
Raw Permalink Normal View History

2026-04-16 22:38:20 +02:00
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
2026-08-15 20:56:29 +02:00
<link rel="prev" href="../formats/index_layout/">
2026-04-16 22:38:20 +02:00
<link rel="icon" href="../assets/images/favicon.png">
2026-04-16 22:38:20 +02:00
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
2026-08-15 20:56:29 +02:00
<title>Architecture notes - obikmer — User Guide</title>
2026-04-16 22:38:20 +02:00
<link rel="stylesheet" href="../assets/stylesheets/main.484c7ddc.min.css">
2026-04-16 22:38:20 +02:00
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
2026-04-16 22:38:20 +02:00
</head>
<body dir="ltr">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
2026-08-15 20:56:29 +02:00
<a href="#architecture-notes-for-advanced-use" class="md-skip">
2026-04-16 22:38:20 +02:00
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
2026-08-15 20:56:29 +02:00
<a href=".." title="obikmer — User Guide" class="md-header__button md-logo" aria-label="obikmer — User Guide" data-md-component="logo">
2026-04-16 22:38:20 +02:00
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
obikmer — User Guide
2026-04-16 22:38:20 +02:00
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Architecture notes
2026-04-16 22:38:20 +02:00
</span>
</div>
</div>
</div>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
2026-08-15 20:56:29 +02:00
<a href=".." title="obikmer — User Guide" class="md-nav__button md-logo" aria-label="obikmer — User Guide" data-md-component="logo">
2026-04-16 22:38:20 +02:00
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
2026-08-15 20:56:29 +02:00
obikmer — User Guide
2026-04-16 22:38:20 +02:00
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
Home
</span>
</a>
</li>
2026-08-15 20:56:29 +02:00
<li class="md-nav__item">
<a href="../installation/" class="md-nav__link">
<span class="md-ellipsis">
2026-04-16 22:38:20 +02:00
2026-08-15 20:56:29 +02:00
Installation
</span>
</a>
</li>
2026-04-16 22:38:20 +02:00
2026-08-15 20:56:29 +02:00
<li class="md-nav__item md-nav__item--nested">
2026-04-16 22:38:20 +02:00
2026-08-15 20:56:29 +02:00
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
2026-04-16 22:38:20 +02:00
2026-08-15 20:56:29 +02:00
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
Theory
</span>
<span class="md-nav__icon md-icon"></span>
</label>
2026-08-15 20:56:29 +02:00
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
2026-04-16 22:38:20 +02:00
<span class="md-nav__icon md-icon"></span>
Theory
</label>
<ul class="md-nav__list" data-md-scrollfix>
2026-08-15 20:56:29 +02:00
<li class="md-nav__item">
<a href="../theory/kmers_and_superkmers/" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
Kmers and super-kmers
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../theory/encoding/" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
DNA encoding
</span>
</a>
</li>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="../theory/entropy_filter/" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Low-complexity kmer filter
2026-04-16 22:38:20 +02:00
</span>
</a>
</li>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="../theory/minimizer_selection/" class="md-nav__link">
<span class="md-ellipsis">
Minimizer selection
</span>
</a>
</li>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="../theory/indexing_architecture/" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Partitioning and indexing architecture
</span>
</a>
</li>
2026-04-16 22:38:20 +02:00
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Usage
2026-04-16 22:38:20 +02:00
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
2026-08-15 20:56:29 +02:00
Usage
2026-04-16 22:38:20 +02:00
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="../usage/superkmer/" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
superkmer
2026-04-16 22:38:20 +02:00
</span>
</a>
</li>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="../usage/index_command/" class="md-nav__link">
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
index
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/merge/" class="md-nav__link">
<span class="md-ellipsis">
merge
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/filter/" class="md-nav__link">
<span class="md-ellipsis">
filter
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/select/" class="md-nav__link">
<span class="md-ellipsis">
select
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/query/" class="md-nav__link">
<span class="md-ellipsis">
query
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/dump/" class="md-nav__link">
<span class="md-ellipsis">
dump
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/annotate/" class="md-nav__link">
<span class="md-ellipsis">
annotate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/phylo/" class="md-nav__link">
<span class="md-ellipsis">
phylo
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/name-tree/" class="md-nav__link">
<span class="md-ellipsis">
name-tree
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/unitig/" class="md-nav__link">
<span class="md-ellipsis">
unitig
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/estimate/" class="md-nav__link">
<span class="md-ellipsis">
estimate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/reindex/" class="md-nav__link">
<span class="md-ellipsis">
reindex
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/utils/" class="md-nav__link">
<span class="md-ellipsis">
utils
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/pack/" class="md-nav__link">
<span class="md-ellipsis">
pack
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../usage/predicates/" class="md-nav__link">
<span class="md-ellipsis">
Predicates and taxonomy paths
</span>
</a>
</li>
2026-04-16 22:38:20 +02:00
</ul>
</nav>
</li>
2026-08-15 20:56:29 +02:00
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Formats
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Formats
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../formats/index_layout/" class="md-nav__link">
<span class="md-ellipsis">
Index construction and on-disk layout
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Architecture notes
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Architecture notes
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#sequence-invariant" class="md-nav__link">
<span class="md-ellipsis">
Sequence invariant
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-dimensioning" class="md-nav__link">
<span class="md-ellipsis">
Index dimensioning
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#parallel-execution-and-numa-awareness" class="md-nav__link">
<span class="md-ellipsis">
Parallel execution and NUMA awareness
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#kmer-filtering-filter" class="md-nav__link">
<span class="md-ellipsis">
Kmer filtering (filter)
</span>
</a>
</li>
</ul>
</nav>
</li>
2026-04-16 22:38:20 +02:00
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="#sequence-invariant" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Sequence invariant
2026-04-16 22:38:20 +02:00
</span>
</a>
</li>
<li class="md-nav__item">
2026-08-15 20:56:29 +02:00
<a href="#index-dimensioning" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Index dimensioning
2026-04-16 22:38:20 +02:00
</span>
</a>
</li>
2026-08-15 20:56:29 +02:00
<li class="md-nav__item">
<a href="#parallel-execution-and-numa-awareness" class="md-nav__link">
2026-04-16 22:38:20 +02:00
<span class="md-ellipsis">
2026-08-15 20:56:29 +02:00
Parallel execution and NUMA awareness
2026-04-16 22:38:20 +02:00
</span>
</a>
</li>
2026-08-15 20:56:29 +02:00
<li class="md-nav__item">
<a href="#kmer-filtering-filter" class="md-nav__link">
<span class="md-ellipsis">
Kmer filtering (filter)
</span>
</a>
2026-04-16 22:38:20 +02:00
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
2026-08-15 20:56:29 +02:00
<h1 id="architecture-notes-for-advanced-use">Architecture notes for advanced use</h1>
<p>This page describes execution-level behavior relevant to sizing and running <code>obikmer</code> on large datasets or multi-socket machines. It complements the <a href="../formats/index_layout/">index format</a> and <a href="../theory/indexing_architecture/">theory</a> pages.</p>
<h2 id="sequence-invariant">Sequence invariant</h2>
<p>Every input sequence is treated purely as a compact representation of a set of overlapping kmers:</p>
2026-04-16 22:38:20 +02:00
<ul>
2026-08-15 20:56:29 +02:00
<li>Only the <code>A</code>/<code>C</code>/<code>G</code>/<code>T</code> alphabet (case-insensitive) is recognized; a sequence is cut at any other character (including IUPAC ambiguity codes), so runs containing them are not represented in the index.</li>
<li>Sequences are internally processed in chunks of at most 256 nucleotides; a chunk shorter than k is dropped. This is invisible to the user beyond the ACGT-only, minimum-length-k constraints above.</li>
<li>Kmers are always handled in canonical form (see <a href="../theory/encoding/">DNA encoding</a>), so the tool is strand-agnostic throughout: a kmer and its reverse complement are always the same entry.</li>
2026-04-16 22:38:20 +02:00
</ul>
2026-08-15 20:56:29 +02:00
<h2 id="index-dimensioning">Index dimensioning</h2>
<p>An index directory is organized as <code>KmerIndex → partitions → layers</code>, with a canonical kmer belonging to exactly one (partition, layer) pair. This is what makes set operations (merge, filter, distance) parallel and coordination-free across partitions.</p>
<ul>
<li><strong>Partition count</strong> (<code>-p</code>/<code>--partitions</code>, rounded up to a power of 2) is the main dimensioning knob: more partitions means more independent parallel units and a smaller working set per partition, at the cost of more open files during construction.</li>
<li><strong>Layers</strong> accumulate as an index grows through successive merges; per-partition query cost grows with the number of layers (worst case linear, expected constant since most kmer lookups resolve in the first layer they could plausibly be in).</li>
<li>Genome columns (count or presence data) are kept at a consistent width across every layer and partition after a merge, which is what allows whole-index aggregate distances (Jaccard, Bray-Curtis, Euclidean, Hellinger, …) to be computed as a two-pass cascade (local partial sums per partition, then a global combination) with no double counting.</li>
</ul>
<h2 id="parallel-execution-and-numa-awareness">Parallel execution and NUMA awareness</h2>
<p>Partition-level work (index construction, <code>merge</code>, <code>filter</code>, <code>reindex</code>, <code>select</code>, <code>phylo</code>'s sibling-annex/Sankoff computations) is dispatched by a partition runner that adapts to the machine's memory topology, detected automatically at startup via hwloc:</p>
<ul>
<li>On a multi-socket / multi-NUMA-node machine, one thread pool is pinned per NUMA node, and each partition is processed entirely by threads pinned to one node — keeping the memory a partition touches local to that node's DRAM. This matters because touching kmer data across NUMA nodes without pinning can degrade throughput by an order of magnitude or more on large multi-socket machines.</li>
<li>On a single-socket machine, Apple Silicon, or if hwloc cannot report NUMA topology, all cores are treated as one node with no pinning and negligible overhead — this is the default behavior on macOS.</li>
<li>Within a node, the number of active worker threads ramps up progressively rather than being fixed up front: it starts conservatively and grows in steps, but only as long as measured CPU efficiency or disk I/O throughput keeps improving. If neither improves after a growth step, the runner stops adding workers — avoiding oversubscription on stages that are memory-bandwidth-bound rather than CPU- or I/O-bound. Ramp speed scales with the number of cores per node, so a single-node machine ramps just as fast as a large multi-node one.</li>
</ul>
<p>No CLI flag controls this directly; it is fully automatic at runtime. NUMA-aware pinning can be compiled out (Cargo feature <code>numa</code>, on by default), in which case a plain global thread pool is used instead.</p>
<h2 id="kmer-filtering-filter">Kmer filtering (<code>filter</code>)</h2>
<p><a href="../usage/filter/"><code>filter</code></a> evaluates predicates against the genome metadata matrix directly whenever every active filter can be expressed as a column-level test (e.g. "any outgroup column non-zero"), producing a per-slot keep/drop decision without touching kmer sequence data at all. If any active filter cannot be expressed this way, evaluation falls back to a per-kmer, row-level check. Either way, the result is always written as a single, freshly compacted layer (<code>unitigs.bin</code> and the MPHF are rebuilt from the surviving kmers), never as an additional layer on top of the source index.</p>
2026-04-16 22:38:20 +02:00
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "..", "features": [], "search": "../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
2026-04-16 22:38:20 +02:00
<script src="../assets/javascripts/bundle.79ae519e.min.js"></script>
2026-04-16 22:38:20 +02:00
<script src="https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js"></script>
</body>
</html>