Skip to content
Merged
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
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

- added `pangraph merge` command, to combine two existing pangenome graphs into a single one, see #197.
- `pangraph build` now accepts a single input sequence, and rejects inputs with duplicate genome names.
- more strict checks on input sequences ids: duplicated or empty ids are now rejected. The `--verify` options compare the input sequence by id and not by order.
- graphs read from a JSON file are now validated before use, in release builds too. A graph whose block, node or path references do not resolve, or whose node positions or alignment edits fall outside the sequences they index, is reported as an error naming the offending file, instead of aborting the process with a panic.
- more strict checks on input sequence ids: duplicated or empty ids are now rejected. The `--verify` options compare the input sequences by id and not by order.
- added more graph validation at loading.
- block and node identifiers are now derived from genome names instead of the order the input sequences are read in, enforcing order-independence.
- fixed a race condition in `pangraph build` that could produce slightly different graphs on repeated runs over the same input.

## 1.3.0

Expand Down
8 changes: 4 additions & 4 deletions docs/docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,14 @@ Merge two pangenome graphs into a single one

###### **Arguments:**

* `<LEFT_GRAPH>` — Path to the first input graph, in pangraph JSON format.

This graph is treated as the base: its block, node and path identifiers are preserved in the output, while those of the second graph are renumbered. When extending an existing graph with new genomes, pass the existing graph here.
* `<LEFT_GRAPH>` — Path to the first input graph, in pangraph JSON format. This graph is treated as the base.

Accepts plain or compressed files. Supported compression formats: `gz`, `bz2`, `xz`, `zstd`. The decompressor is chosen based on the file extension.
* `<RIGHT_GRAPH>` — Path to the second input graph, in pangraph JSON format.

Its identifiers are renumbered so that they do not clash with those of the first graph. Its genomes appear after those of the first graph in the output.
Its path identifiers are renumbered to follow those of the first graph, so its genomes appear after them in the output.

Accepts plain or compressed files. Supported compression formats: `gz`, `bz2`, `xz`, `zstd`. The decompressor is chosen based on the file extension.

###### **Options:**

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/tutorial/t04b-merging-two-graphs.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The two graphs can then be merged:
pangraph merge graph.json k12.json -o graph_11.json
```

The resulting `graph_11.json` contains 11 paths: the 10 genomes of `graph.json`, in their original order, followed by K-12. Adding the eleventh chromosome created comparatively few new blocks (2896 2943): most of it was absorbed into blocks that already existed.
The resulting `graph_11.json` contains 11 paths: the 10 genomes of `graph.json`, in their original order, followed by K-12. Adding the eleventh chromosome created comparatively few new blocks (2896 -> 2943): most of it was absorbed into blocks that already existed.

On a consumer laptop the merge takes around 20 seconds, against the roughly 3.5 minutes needed to build the 10-genome graph in the first place.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ fn align_with_minimap2_lib_impl(

let idx = Minimap2Index::new(&seqs, &names, &args)?;

// Collected into a `Vec` first so that the parallel iterator is *indexed*: `par_bridge` hands
// work out in whatever order threads ask for it and collects in that order, which made the hit
// list vary between runs. `filter_matches` then broke equal-energy ties differently, so the same
// input could build different graphs. `Vec::into_par_iter` restores input order.
let results: Vec<Minimap2Result> = izip!(&seqs, &names)
.par_bridge()
.collect_vec()
.into_par_iter()
.map_init(
|| Minimap2Mapper::new(&idx).unwrap(),
move |mapper, (seq, name)| {
Expand Down
50 changes: 25 additions & 25 deletions packages/pangraph/src/circularize/circularize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,28 +110,28 @@ mod tests {

#[rustfmt::skip]
let nodes = btreemap! {
NodeId(10) => PangraphNode::new(Some(NodeId(10)), BlockId(1), PathId(0), Forward, (0, 0)),
NodeId(20) => PangraphNode::new(Some(NodeId(20)), BlockId(2), PathId(0), Forward, (0, 0)),
NodeId(30) => PangraphNode::new(Some(NodeId(30)), BlockId(3), PathId(0), Forward, (0, 0)),
NodeId(40) => PangraphNode::new(Some(NodeId(40)), BlockId(4), PathId(0), Forward, (0, 0)),
NodeId(11) => PangraphNode::new(Some(NodeId(11)), BlockId(1), PathId(1), Forward, (0, 0)),
NodeId(21) => PangraphNode::new(Some(NodeId(21)), BlockId(2), PathId(1), Reverse, (0, 0)),
NodeId(22) => PangraphNode::new(Some(NodeId(22)), BlockId(2), PathId(1), Forward, (0, 0)),
NodeId(31) => PangraphNode::new(Some(NodeId(31)), BlockId(3), PathId(1), Forward, (0, 0)),
NodeId(41) => PangraphNode::new(Some(NodeId(41)), BlockId(4), PathId(1), Forward, (0, 0)),
NodeId(12) => PangraphNode::new(Some(NodeId(12)), BlockId(1), PathId(2), Forward, (0, 0)),
NodeId(23) => PangraphNode::new(Some(NodeId(23)), BlockId(2), PathId(2), Forward, (0, 0)),
NodeId(32) => PangraphNode::new(Some(NodeId(32)), BlockId(3), PathId(2), Reverse, (0, 0)),
NodeId(42) => PangraphNode::new(Some(NodeId(42)), BlockId(4), PathId(2), Forward, (0, 0)),
NodeId(13) => PangraphNode::new(Some(NodeId(13)), BlockId(1), PathId(3), Forward, (0, 0)),
NodeId(33) => PangraphNode::new(Some(NodeId(33)), BlockId(3), PathId(3), Reverse, (0, 0)),
NodeId(24) => PangraphNode::new(Some(NodeId(24)), BlockId(2), PathId(3), Forward, (0, 0)),
NodeId(34) => PangraphNode::new(Some(NodeId(34)), BlockId(3), PathId(3), Reverse, (0, 0)),
NodeId(43) => PangraphNode::new(Some(NodeId(43)), BlockId(4), PathId(3), Forward, (0, 0)),
NodeId(44) => PangraphNode::new(Some(NodeId(44)), BlockId(4), PathId(4), Reverse, (0, 0)),
NodeId(35) => PangraphNode::new(Some(NodeId(35)), BlockId(3), PathId(4), Reverse, (0, 0)),
NodeId(25) => PangraphNode::new(Some(NodeId(25)), BlockId(2), PathId(4), Reverse, (0, 0)),
NodeId(14) => PangraphNode::new(Some(NodeId(14)), BlockId(1), PathId(4), Reverse, (0, 0)),
NodeId(10) => PangraphNode::new(NodeId(10), BlockId(1), PathId(0), Forward, (0, 0)),
NodeId(20) => PangraphNode::new(NodeId(20), BlockId(2), PathId(0), Forward, (0, 0)),
NodeId(30) => PangraphNode::new(NodeId(30), BlockId(3), PathId(0), Forward, (0, 0)),
NodeId(40) => PangraphNode::new(NodeId(40), BlockId(4), PathId(0), Forward, (0, 0)),
NodeId(11) => PangraphNode::new(NodeId(11), BlockId(1), PathId(1), Forward, (0, 0)),
NodeId(21) => PangraphNode::new(NodeId(21), BlockId(2), PathId(1), Reverse, (0, 0)),
NodeId(22) => PangraphNode::new(NodeId(22), BlockId(2), PathId(1), Forward, (0, 0)),
NodeId(31) => PangraphNode::new(NodeId(31), BlockId(3), PathId(1), Forward, (0, 0)),
NodeId(41) => PangraphNode::new(NodeId(41), BlockId(4), PathId(1), Forward, (0, 0)),
NodeId(12) => PangraphNode::new(NodeId(12), BlockId(1), PathId(2), Forward, (0, 0)),
NodeId(23) => PangraphNode::new(NodeId(23), BlockId(2), PathId(2), Forward, (0, 0)),
NodeId(32) => PangraphNode::new(NodeId(32), BlockId(3), PathId(2), Reverse, (0, 0)),
NodeId(42) => PangraphNode::new(NodeId(42), BlockId(4), PathId(2), Forward, (0, 0)),
NodeId(13) => PangraphNode::new(NodeId(13), BlockId(1), PathId(3), Forward, (0, 0)),
NodeId(33) => PangraphNode::new(NodeId(33), BlockId(3), PathId(3), Reverse, (0, 0)),
NodeId(24) => PangraphNode::new(NodeId(24), BlockId(2), PathId(3), Forward, (0, 0)),
NodeId(34) => PangraphNode::new(NodeId(34), BlockId(3), PathId(3), Reverse, (0, 0)),
NodeId(43) => PangraphNode::new(NodeId(43), BlockId(4), PathId(3), Forward, (0, 0)),
NodeId(44) => PangraphNode::new(NodeId(44), BlockId(4), PathId(4), Reverse, (0, 0)),
NodeId(35) => PangraphNode::new(NodeId(35), BlockId(3), PathId(4), Reverse, (0, 0)),
NodeId(25) => PangraphNode::new(NodeId(25), BlockId(2), PathId(4), Reverse, (0, 0)),
NodeId(14) => PangraphNode::new(NodeId(14), BlockId(1), PathId(4), Reverse, (0, 0)),
};

#[rustfmt::skip]
Expand Down Expand Up @@ -216,9 +216,9 @@ mod tests {
BlockId(1) => block_1()
};
let nodes = btreemap! {
NodeId(1) => PangraphNode::new(Some(NodeId(1)), BlockId(1), PathId(1), Forward, (0, 32)),
NodeId(2) => PangraphNode::new(Some(NodeId(2)), BlockId(1), PathId(2), Forward, (0, 31)),
NodeId(3) => PangraphNode::new(Some(NodeId(3)), BlockId(1), PathId(3), Reverse, (0, 35))
NodeId(1) => PangraphNode::new(NodeId(1), BlockId(1), PathId(1), Forward, (0, 32)),
NodeId(2) => PangraphNode::new(NodeId(2), BlockId(1), PathId(2), Forward, (0, 31)),
NodeId(3) => PangraphNode::new(NodeId(3), BlockId(1), PathId(3), Reverse, (0, 35))
};
Pangraph { paths, blocks, nodes }
}
Expand Down
Loading
Loading