From f2e09c8ef61a1c4fd139d9455b3fab4404cdc344 Mon Sep 17 00:00:00 2001 From: kojix2 <2xijok@gmail.com> Date: Wed, 21 Jun 2023 13:05:13 +0900 Subject: [PATCH 01/41] add macos to CI --- .github/workflows/build_and_test_on_push.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test_on_push.yml b/.github/workflows/build_and_test_on_push.yml index 582a1b658..477d1da5e 100644 --- a/.github/workflows/build_and_test_on_push.yml +++ b/.github/workflows/build_and_test_on_push.yml @@ -3,7 +3,7 @@ on: [ push ] name: build and test jobs: - build_and_test: + linux: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -27,3 +27,20 @@ jobs: run: ASAN_OPTIONS=detect_leaks=1:symbolize=1 LSAN_OPTIONS=verbosity=0:log_threads=1 bin/odgi test - name: Run remaining tests run: ctest --test-dir build -E odgi-test --verbose + + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Install required packages + run: brew update && brew install cmake llvm jemalloc + - name: Init and update submodules + run: git submodule update --init --recursive + - name: Build odgi + run: | + CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ LDFLAGS=-L/opt/homebrew/lib cmake . -Bbuild + CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ LDFLAGS=-L/opt/homebrew/lib cmake --build build -- -j + - name: Run odgi program tests + run: ASAN_OPTIONS=detect_leaks=1:symbolize=1 LSAN_OPTIONS=verbosity=0:log_threads=1 bin/odgi test + - name: Run remaining tests + run: ctest --test-dir build -E odgi-test --verbose From 85a22bf34d013ffcfa52db671e239a37942deb5e Mon Sep 17 00:00:00 2001 From: kojix2 <2xijok@gmail.com> Date: Wed, 21 Jun 2023 14:09:34 +0900 Subject: [PATCH 02/41] update workflow to trigger on push and pull_request --- .github/workflows/build_and_test_on_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test_on_push.yml b/.github/workflows/build_and_test_on_push.yml index 477d1da5e..37e626a12 100644 --- a/.github/workflows/build_and_test_on_push.yml +++ b/.github/workflows/build_and_test_on_push.yml @@ -1,4 +1,4 @@ -on: [ push ] +on: [ push, pull_request ] name: build and test From fa9b1c0e2dba9c714cc015eaee070a572d1eafd3 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 22 Jun 2023 13:49:24 +0200 Subject: [PATCH 03/41] heaps: plot down to 0 on the y-axis --- scripts/heaps_fit.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/heaps_fit.R b/scripts/heaps_fit.R index f77b8a8a6..6e2338acd 100644 --- a/scripts/heaps_fit.R +++ b/scripts/heaps_fit.R @@ -32,5 +32,5 @@ print(z * (f(n) - f(n-1))) print(z * (f(2) - f(1))) #print(f(n) - f(n-1)) pdf(NULL) -ggplot(x, aes(x=nth.genome, y=base.pairs/1e9)) + geom_point(alpha=I(1/10)) + stat_function(fun=function(x) (fit$par[1] * x^fit$par[2] + fit$par[3]) * m) + scale_y_continuous("observed pangenome size (Gbp)") + scale_x_continuous(paste("Nth included genome (", max(x$permutation)+1 ," permutations) with gamma=", round(fit$par[2], digits=3), sep = "")) +ggplot(x, aes(x=nth.genome, y=base.pairs/1e9)) + geom_point(alpha=I(1/10)) + stat_function(fun=function(x) (fit$par[1] * x^fit$par[2] + fit$par[3]) * m) + scale_y_continuous("observed pangenome size (Gbp)") + scale_x_continuous(paste("Nth included genome (", max(x$permutation)+1 ," permutations) with gamma=", round(fit$par[2], digits=3), sep = "")) + expand_limits(x = 0, y = 0) ggsave(args[2], height=5, width=9) From 07c08228a5d67b04b5b7e04997fc55ce50c6563e Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Mon, 3 Jul 2023 16:59:00 +0200 Subject: [PATCH 04/41] progress in `odgi pav` --- src/subcommand/pav_main.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/subcommand/pav_main.cpp b/src/subcommand/pav_main.cpp index 02b2b81db..08a00ef7c 100644 --- a/src/subcommand/pav_main.cpp +++ b/src/subcommand/pav_main.cpp @@ -119,7 +119,7 @@ int main_pav(int argc, char **argv) { auto vals = split(line, '\t'); if (vals.size() != 2) { std::cerr << "[odgi::pav] line does not have a path.name and path.group value:" - << std::endl << line << std::endl; + << std::endl << line << std::endl; return 1; } auto& path_name = vals.front(); @@ -136,8 +136,8 @@ int main_pav(int argc, char **argv) { if (group_2_index.empty()) { std::cerr - << "[odgi::pav] error: 0 path groups were read. Please specify at least one path group via -p/--path-groups." - << std::endl; + << "[odgi::pav] error: 0 path groups were read. Please specify at least one path group via -p/--path-groups." + << std::endl; return 1; } } else if (_group_by_sample) { @@ -185,7 +185,6 @@ int main_pav(int argc, char **argv) { add_bed_range(path_ranges, graph, line); } } - if (path_ranges.empty()) { std::cerr << "[odgi::pav] error: please specify path ranges via -b/--bed-file." @@ -225,7 +224,12 @@ int main_pav(int argc, char **argv) { path_handle_2_index[p2mm.first] = i++; } - // Prepare the interval trees to query target path ranges + // Prepare the interval trees for querying target path ranges + std::unique_ptr operation_progress; + if (show_progress) { + std::string banner = "[odgi::pav] preparing the interval trees for querying target path ranges:"; + operation_progress = std::make_unique(path_handles.size(), banner); + } std::vector> trees; trees.resize(path_handles.size()); #pragma omp parallel for schedule(dynamic, 1) num_threads(num_threads) @@ -250,7 +254,12 @@ int main_pav(int argc, char **argv) { } tree.index(); // index + + if (show_progress) { + operation_progress->increment(1); + } } + operation_progress->finish(); const bool emit_matrix_else_table = args::get(_matrix_output); @@ -296,6 +305,11 @@ int main_pav(int argc, char **argv) { << (emit_binary_values ? pav_ratio >= binary_threshold : pav_ratio) << "\n"; }; + if (show_progress) { + std::string banner = "[odgi::pav] emitting PAV results:"; + operation_progress = std::make_unique(path_ranges.size(), banner); + } + #pragma omp parallel for schedule(dynamic, 1) num_threads(num_threads) for (uint64_t i = 0; i < path_ranges.size(); ++i) { auto &path_range = path_ranges[i]; @@ -386,7 +400,13 @@ int main_pav(int argc, char **argv) { } } } + + + if (show_progress) { + operation_progress->increment(1); + } } + operation_progress->finish(); return 0; } From d650d9253c13214ac5c04267e56128c084f91d6e Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Fri, 14 Jul 2023 10:12:44 +0200 Subject: [PATCH 05/41] fix vector size --- src/subcommand/similarity_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/subcommand/similarity_main.cpp b/src/subcommand/similarity_main.cpp index 0d241d2dd..da913e3ce 100644 --- a/src/subcommand/similarity_main.cpp +++ b/src/subcommand/similarity_main.cpp @@ -162,7 +162,7 @@ args::Group threading_opts(parser, "[ Threading ]"); if (using_delim) { bp_count.resize(path_groups.size()); } else { - bp_count.resize(graph.get_path_count()); + bp_count.resize(graph.get_path_count() + 1); } uint32_t path_max = 0; From f2cf727a3123bce8ac08b93361e08d0059c5f135 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Fri, 14 Jul 2023 10:15:06 +0200 Subject: [PATCH 06/41] enable ASAN in the github workflow --- .github/workflows/build_and_test_on_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test_on_push.yml b/.github/workflows/build_and_test_on_push.yml index 37e626a12..652695921 100644 --- a/.github/workflows/build_and_test_on_push.yml +++ b/.github/workflows/build_and_test_on_push.yml @@ -22,7 +22,7 @@ jobs: - name: Init and update submodules run: git submodule update --init --recursive - name: Build odgi - run: cmake -H. -DCMAKE_BUILD_TYPE=Debug -Bbuild && cmake --build build -- -j 2 + run: cmake -H. -DCMAKE_BUILD_TYPE=Debug -DASAN=ON -Bbuild && cmake --build build -- -j 2 - name: Run odgi program tests run: ASAN_OPTIONS=detect_leaks=1:symbolize=1 LSAN_OPTIONS=verbosity=0:log_threads=1 bin/odgi test - name: Run remaining tests From 97829435ebdf8bc20a4171ba791a6d37efd5671b Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Fri, 14 Jul 2023 10:44:01 +0200 Subject: [PATCH 07/41] no ASAN for now --- .github/workflows/build_and_test_on_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test_on_push.yml b/.github/workflows/build_and_test_on_push.yml index 652695921..37e626a12 100644 --- a/.github/workflows/build_and_test_on_push.yml +++ b/.github/workflows/build_and_test_on_push.yml @@ -22,7 +22,7 @@ jobs: - name: Init and update submodules run: git submodule update --init --recursive - name: Build odgi - run: cmake -H. -DCMAKE_BUILD_TYPE=Debug -DASAN=ON -Bbuild && cmake --build build -- -j 2 + run: cmake -H. -DCMAKE_BUILD_TYPE=Debug -Bbuild && cmake --build build -- -j 2 - name: Run odgi program tests run: ASAN_OPTIONS=detect_leaks=1:symbolize=1 LSAN_OPTIONS=verbosity=0:log_threads=1 bin/odgi test - name: Run remaining tests From 811e9696e93745253171ad37026e3560caffa16c Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sun, 6 Aug 2023 21:16:59 +0200 Subject: [PATCH 08/41] -O option to optimize the extracted graph --- src/subcommand/extract_main.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/subcommand/extract_main.cpp b/src/subcommand/extract_main.cpp index e1737eb46..a192f4b71 100644 --- a/src/subcommand/extract_main.cpp +++ b/src/subcommand/extract_main.cpp @@ -84,6 +84,8 @@ namespace odgi { "List of paths to fully retain in the extracted graph. Must " "contain one path name per line and a subset of all paths can be specified.", {'R', "lace-paths"}); + args::Flag _optimize(extract_opts, "optimize", "Compact the node ID space in the extracted graph(s).", + {'O', "optimize"}); args::Group threading_opts(parser, "[ Threading ]"); args::ValueFlag nthreads(threading_opts, "N", "Number of threads to use for parallel operations.", {'t', "threads"}); @@ -384,6 +386,7 @@ namespace odgi { const bool show_progress = args::get(_show_progress); + const bool optimize = args::get(_optimize); const uint64_t context_steps = _context_steps ? args::get(_context_steps) : 0; const uint64_t context_bases = _context_bases ? args::get(_context_bases) : 0; @@ -395,7 +398,7 @@ namespace odgi { std::vector path_ranges, std::vector> pangenomic_ranges, const uint64_t context_steps, const uint64_t context_bases, const bool full_range, const bool inverse, const uint64_t max_dist_subpaths, const uint64_t num_iterations, - const uint64_t num_threads, const bool show_progress) { + const uint64_t num_threads, const bool show_progress, const bool optimize) { if (context_steps > 0 || context_bases > 0) { if (show_progress) { std::cerr << "[odgi::extract] expansion and adding connecting edges" << std::endl; @@ -717,6 +720,10 @@ namespace odgi { // This should not be necessary, if the extraction works correctly // subgraph.remove_orphan_edges(); + + if (optimize) { + subgraph.optimize(); + } }; auto check_and_create_handle = [&](const graph_t &source, graph_t &subgraph, const nid_t node_id) { @@ -744,7 +751,13 @@ namespace odgi { << path_range.end.offset << std::endl; } - prep_graph(graph, &paths, lace_paths, subgraph, {path_range}, *pangenomic_ranges, context_steps, context_bases, _full_range, false, args::get(_max_dist_subpaths), num_iterations, num_threads, show_progress); + prep_graph( + graph, &paths, + lace_paths, subgraph, + {path_range}, *pangenomic_ranges, + context_steps, context_bases, _full_range, false, + args::get(_max_dist_subpaths), num_iterations, + num_threads, show_progress, optimize); const string filename = graph.get_path_name(path_range.begin.path) + ":" + to_string(path_range.begin.offset) + "-" + to_string(path_range.end.offset) + ".og"; @@ -771,7 +784,13 @@ namespace odgi { } } - prep_graph(graph, &paths, lace_paths, subgraph, *path_ranges, *pangenomic_ranges, context_steps, context_bases, _full_range, _inverse, args::get(_max_dist_subpaths), num_iterations, num_threads, show_progress); + prep_graph( + graph, &paths, + lace_paths, subgraph, + *path_ranges, *pangenomic_ranges, + context_steps, context_bases, _full_range, _inverse, + args::get(_max_dist_subpaths), num_iterations, + num_threads, show_progress, optimize); { const std::string outfile = args::get(og_out_file); From 4ca7e85f4dad6bade61e655873047ad5e0f0da2a Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sun, 6 Aug 2023 21:26:12 +0200 Subject: [PATCH 09/41] -d is not mandatory anymore, 100kbp by default --- src/subcommand/extract_main.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/subcommand/extract_main.cpp b/src/subcommand/extract_main.cpp index a192f4b71..9a7da9a5b 100644 --- a/src/subcommand/extract_main.cpp +++ b/src/subcommand/extract_main.cpp @@ -31,16 +31,16 @@ namespace odgi { args::Group graph_files_io_opts(parser, "[ Graph Files IO ]"); args::ValueFlag og_out_file(graph_files_io_opts, "FILE", "Store all subgraphs in this FILE. The file name usually ends with *.og*.", {'o', "out"}); - args::ValueFlag _max_dist_subpaths(mandatory_opts, "N", + args::Group extract_opts(parser, "[ Extract Options ]"); + args::ValueFlag _max_dist_subpaths(extract_opts, "N", "Maximum distance between subpaths allowed for merging them. " "It reduces the fragmentation of unspecified paths in the input path ranges. " - "Set 0 to disable it.", + "Set 0 to disable it [default: 100000].", {'d', "max-distance-subpaths"}); - args::ValueFlag _num_iterations(mandatory_opts, "N", + args::ValueFlag _num_iterations(extract_opts, "N", "Maximum number of iterations in attempting to merge close subpaths. " "It stops early if during an iteration no subpaths were merged [default: 3].", {'e', "max-merging-iterations"}); - args::Group extract_opts(parser, "[ Extract Options ]"); args::Flag _split_subgraphs(extract_opts, "split_subgraphs", "Instead of writing the target subgraphs into a single graph, " "write one subgraph per given target to a separate file named path:start-end.og " @@ -118,10 +118,6 @@ namespace odgi { return 1; } - if (!_max_dist_subpaths) { - std::cerr << "[odgi::extract] error: please specify -d/--max-distance-subpaths. Values equal to or greater than 0 are allowed." << std::endl; - return 1; - } if ((!_max_dist_subpaths || args::get(_max_dist_subpaths) == 0) && _num_iterations) { std::cerr << "[odgi::extract] error: specified -e/--max-merging-iterations without specifying -d/--max-distance-subpaths greater than 0." << std::endl; return 1; @@ -138,7 +134,8 @@ namespace odgi { return 1; } - const uint64_t num_iterations = _num_iterations && args::get(_num_iterations) > 0 ? args::get(_num_iterations) : 3; + const uint64_t max_dist_subpaths = _max_dist_subpaths && args::get(_max_dist_subpaths) >= 0 ? args::get(_max_dist_subpaths) : 100000; + const uint64_t num_iterations = _num_iterations && args::get(_num_iterations) > 0 ? args::get(_num_iterations) : 3; if (_split_subgraphs) { if (og_out_file) { @@ -756,7 +753,7 @@ namespace odgi { lace_paths, subgraph, {path_range}, *pangenomic_ranges, context_steps, context_bases, _full_range, false, - args::get(_max_dist_subpaths), num_iterations, + max_dist_subpaths, num_iterations, num_threads, show_progress, optimize); const string filename = graph.get_path_name(path_range.begin.path) + ":" + to_string(path_range.begin.offset) + "-" + to_string(path_range.end.offset) + ".og"; @@ -789,7 +786,7 @@ namespace odgi { lace_paths, subgraph, *path_ranges, *pangenomic_ranges, context_steps, context_bases, _full_range, _inverse, - args::get(_max_dist_subpaths), num_iterations, + max_dist_subpaths, num_iterations, num_threads, show_progress, optimize); { From 8a4c05bb01c9d36dcff578fd862fbdab537eeff8 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Mon, 28 Aug 2023 18:15:00 +0200 Subject: [PATCH 10/41] fix bug in reference guided sorting --- src/subcommand/sort_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/subcommand/sort_main.cpp b/src/subcommand/sort_main.cpp index 3347e59d1..109b9e123 100644 --- a/src/subcommand/sort_main.cpp +++ b/src/subcommand/sort_main.cpp @@ -271,6 +271,7 @@ int main_sort(int argc, char** argv) { std::string banner = "[odgi::sort] preparing target path vectors:"; target_paths_progress = std::make_unique(target_paths.size(), banner); } + uint64_t ref_nodes = 0; for (handlegraph::path_handle_t target_path: target_paths) { graph.for_each_step_in_path( target_path, @@ -280,6 +281,7 @@ int main_sort(int argc, char** argv) { if (!is_ref[i]) { is_ref[i] = true; target_order.push_back(handle); + ref_nodes++; } }); if (args::get(progress)) { @@ -289,12 +291,10 @@ int main_sort(int argc, char** argv) { if (args::get(progress)) { target_paths_progress->finish(); } - uint64_t ref_nodes = 0; for (uint64_t i = 0; i < is_ref.size(); i++) { bool ref = is_ref[i]; if (!ref) { target_order.push_back(graph.get_handle(i + 1)); - ref_nodes++; } } graph.apply_ordering(target_order, true); From ca39478b95bcb2a2658fe03144fce3b8972a0605 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Wed, 9 Aug 2023 10:05:35 +0200 Subject: [PATCH 11/41] add `-n/--non-reference-paths` in `odgi paths` --- src/subcommand/paths_main.cpp | 75 ++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index 63223b36b..429b1e85d 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -45,7 +45,8 @@ int main_paths(int argc, char** argv) { {'D', "delim"}); args::ValueFlag path_delim_pos(path_investigation_opts, "N", "Consider the N-th occurrence of the delimiter specified with **-D, --delim**" " to obtain the group identifier. Specify 1 for the 1st occurrence (default).", - {'p', "delim-pos"}); + {'p', "delim-pos"}); + args::ValueFlag non_reference_paths(path_investigation_opts, "FILE", "Print to stdout (in BED format) path ranges that are not in the paths listed (by line) in *FILE*.", {'n', "non-reference-paths"}); args::Group path_modification_opts(parser, "[ Path Modification Options ]"); args::ValueFlag keep_paths_file(path_modification_opts, "FILE", "Keep paths listed (by line) in *FILE*.", {'K', "keep-paths"}); args::ValueFlag drop_paths_file(path_modification_opts, "FILE", "Drop paths listed (by line) in *FILE*.", {'X', "drop-paths"}); @@ -347,6 +348,78 @@ int main_paths(int argc, char** argv) { } } + if (non_reference_paths && !args::get(non_reference_paths).empty()) { + // Check if the node IDs are compacted + const uint64_t shift = graph.min_node_id(); + if (graph.max_node_id() - shift >= graph.get_node_count()){ + std::cerr << "[odgi::paths] error: the node IDs are not compacted. Please run 'odgi sort' using -O, --optimize to optimize the graph." << std::endl; + exit(1); + } + + // Read paths to use as reference paths + std::vector reference_paths; + std::string line; + auto& x = args::get(non_reference_paths); + std::ifstream infile(x); + while (std::getline(infile, line)) { + // This file should contain path names, one per line + auto& name = line; + if (graph.has_path(name)) { + reference_paths.push_back(graph.get_path_handle(name)); + } else { + std::cerr << "[odgi::paths] error: path'" << name + << "' does not exist in graph." << std::endl; + return 1; + } + } + + // Set the reference nodes + atomicbitvector::atomic_bv_t reference_nodes(graph.get_node_count()+1); +#pragma omp parallel for schedule(dynamic,1) + for (auto &path : reference_paths) { + graph.for_each_step_in_path(path, [&](const step_handle_t& step) { + const handle_t handle = graph.get_handle_of_step(step); + reference_nodes.set(graph.get_id(handle) - shift); + }); + } + + std::vector non_reference_paths; + graph.for_each_path_handle([&non_reference_paths](const path_handle_t& path) { + non_reference_paths.push_back(path); + }); + + // Prepare non reference path handles for parallel processing + std::sort(non_reference_paths.begin(), non_reference_paths.end()); + std::sort(reference_paths.begin(), reference_paths.end()); + + non_reference_paths.erase( + std::remove_if(non_reference_paths.begin(), non_reference_paths.end(), + [&reference_paths](const auto &x) { + return std::binary_search(reference_paths.begin(), reference_paths.end(), x); + }), non_reference_paths.end()); + + // Traverse non reference paths to emit non reference ranges +#pragma omp parallel for schedule(dynamic, 1) + for (auto& path : non_reference_paths) { + uint64_t start = 0, end = 0; + graph.for_each_step_in_path(path, [&](const step_handle_t& step) { + const handle_t handle = graph.get_handle_of_step(step); + const uint64_t index = graph.get_id(handle) - shift; + if (reference_nodes.test(index)) { + // Emit the previous non reference range, if any + if (end > start) { + #pragma omp critical (cout) + std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << std::endl; + } + end += graph.get_length(handle); + start = end; + } else { + end += graph.get_length(handle); + } + }); + } + } + return 0; } From f4800594db272616a90235250968acdd86faf809 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Thu, 10 Aug 2023 14:31:58 +0200 Subject: [PATCH 12/41] add `--non-reference-nodes` --- src/subcommand/paths_main.cpp | 132 +++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 42 deletions(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index 429b1e85d..5df01ca49 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -46,7 +46,8 @@ int main_paths(int argc, char** argv) { args::ValueFlag path_delim_pos(path_investigation_opts, "N", "Consider the N-th occurrence of the delimiter specified with **-D, --delim**" " to obtain the group identifier. Specify 1 for the 1st occurrence (default).", {'p', "delim-pos"}); - args::ValueFlag non_reference_paths(path_investigation_opts, "FILE", "Print to stdout (in BED format) path ranges that are not in the paths listed (by line) in *FILE*.", {'n', "non-reference-paths"}); + args::ValueFlag non_reference_nodes(path_investigation_opts, "FILE", "Print to stdout IDs of nodes that are not in the paths listed (by line) in *FILE*.", {"non-reference-nodes"}); + args::ValueFlag non_reference_ranges(path_investigation_opts, "FILE", "Print to stdout (in BED format) path ranges that are not in the paths listed (by line) in *FILE*.", {"non-reference-ranges"}); args::Group path_modification_opts(parser, "[ Path Modification Options ]"); args::ValueFlag keep_paths_file(path_modification_opts, "FILE", "Keep paths listed (by line) in *FILE*.", {'K', "keep-paths"}); args::ValueFlag drop_paths_file(path_modification_opts, "FILE", "Drop paths listed (by line) in *FILE*.", {'X', "drop-paths"}); @@ -93,6 +94,11 @@ int main_paths(int argc, char** argv) { return 1; } + if (non_reference_nodes && non_reference_ranges) { + std::cerr << "[odgi::paths] error: specify --non-reference-nodes or non-reference-ranges, not both." << std::endl; + return 1; + } + const uint64_t num_threads = args::get(threads) ? args::get(threads) : 1; omp_set_num_threads(num_threads); @@ -348,7 +354,10 @@ int main_paths(int argc, char** argv) { } } - if (non_reference_paths && !args::get(non_reference_paths).empty()) { + if ( + (non_reference_nodes && !args::get(non_reference_nodes).empty()) || + (non_reference_ranges && !args::get(non_reference_ranges).empty()) + ) { // Check if the node IDs are compacted const uint64_t shift = graph.min_node_id(); if (graph.max_node_id() - shift >= graph.get_node_count()){ @@ -359,7 +368,7 @@ int main_paths(int argc, char** argv) { // Read paths to use as reference paths std::vector reference_paths; std::string line; - auto& x = args::get(non_reference_paths); + auto& x = non_reference_nodes && !args::get(non_reference_nodes).empty() ? args::get(non_reference_nodes) : args::get(non_reference_ranges); std::ifstream infile(x); while (std::getline(infile, line)) { // This file should contain path names, one per line @@ -373,50 +382,89 @@ int main_paths(int argc, char** argv) { } } - // Set the reference nodes - atomicbitvector::atomic_bv_t reference_nodes(graph.get_node_count()+1); + if (non_reference_nodes && !args::get(non_reference_nodes).empty()){ + // Emit non-reference nodes + + // Set non-reference nodes + atomicbitvector::atomic_bv_t non_reference_nodes(graph.get_node_count()); + for(uint64_t i = 0; i < non_reference_nodes.size(); i++) { + non_reference_nodes.set(i); + } #pragma omp parallel for schedule(dynamic,1) - for (auto &path : reference_paths) { - graph.for_each_step_in_path(path, [&](const step_handle_t& step) { - const handle_t handle = graph.get_handle_of_step(step); - reference_nodes.set(graph.get_id(handle) - shift); - }); - } + for (auto &path : reference_paths) { + graph.for_each_step_in_path(path, [&](const step_handle_t& step) { + const handle_t handle = graph.get_handle_of_step(step); + non_reference_nodes.reset(graph.get_id(handle) - shift); + }); + } - std::vector non_reference_paths; - graph.for_each_path_handle([&non_reference_paths](const path_handle_t& path) { - non_reference_paths.push_back(path); - }); - - // Prepare non reference path handles for parallel processing - std::sort(non_reference_paths.begin(), non_reference_paths.end()); - std::sort(reference_paths.begin(), reference_paths.end()); - - non_reference_paths.erase( - std::remove_if(non_reference_paths.begin(), non_reference_paths.end(), - [&reference_paths](const auto &x) { - return std::binary_search(reference_paths.begin(), reference_paths.end(), x); - }), non_reference_paths.end()); - - // Traverse non reference paths to emit non reference ranges -#pragma omp parallel for schedule(dynamic, 1) - for (auto& path : non_reference_paths) { - uint64_t start = 0, end = 0; - graph.for_each_step_in_path(path, [&](const step_handle_t& step) { - const handle_t handle = graph.get_handle_of_step(step); - const uint64_t index = graph.get_id(handle) - shift; - if (reference_nodes.test(index)) { - // Emit the previous non reference range, if any - if (end > start) { - #pragma omp critical (cout) - std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << std::endl; + // Emit non-reference nodes + std::cout << "#node.id\tpaths" << std::endl; + for (auto x : non_reference_nodes) { + const handle_t handle = graph.get_handle(x + shift); + + // Check paths that go through this node, if any + std::unordered_set unique_path_handles; + graph.for_each_step_on_handle(handle, [&](const step_handle_t& step) { + unique_path_handles.insert(graph.get_path_handle_of_step(step)); + }); + std::string result; + for (const auto& path : unique_path_handles) { + if (!result.empty()) { + result += ","; } - end += graph.get_length(handle); - start = end; - } else { - end += graph.get_length(handle); + result += graph.get_path_name(path); } + + std::cout << graph.get_id(handle) << "\t" << result << std::endl; + } + } else { + // Emit non-reference ranges + + // Set the reference nodes + atomicbitvector::atomic_bv_t reference_nodes(graph.get_node_count()); + #pragma omp parallel for schedule(dynamic,1) + for (auto &path : reference_paths) { + graph.for_each_step_in_path(path, [&](const step_handle_t& step) { + const handle_t handle = graph.get_handle_of_step(step); + reference_nodes.set(graph.get_id(handle) - shift); + }); + } + + // Prepare non reference path handles for parallel processing + std::vector non_reference_paths; + graph.for_each_path_handle([&non_reference_paths](const path_handle_t& path) { + non_reference_paths.push_back(path); }); + std::sort(non_reference_paths.begin(), non_reference_paths.end()); + std::sort(reference_paths.begin(), reference_paths.end()); + non_reference_paths.erase( + std::remove_if(non_reference_paths.begin(), non_reference_paths.end(), + [&reference_paths](const auto &x) { + return std::binary_search(reference_paths.begin(), reference_paths.end(), x); + }), non_reference_paths.end()); + + // Traverse non reference paths to emit non-reference ranges + std::cout << "#path.name\tstart\tend" << std::endl; + #pragma omp parallel for schedule(dynamic, 1) + for (auto& path : non_reference_paths) { + uint64_t start = 0, end = 0; + graph.for_each_step_in_path(path, [&](const step_handle_t& step) { + const handle_t handle = graph.get_handle_of_step(step); + const uint64_t index = graph.get_id(handle) - shift; + if (reference_nodes.test(index)) { + // Emit the previous non reference range, if any + if (end > start) { + #pragma omp critical (cout) + std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << std::endl; + } + end += graph.get_length(handle); + start = end; + } else { + end += graph.get_length(handle); + } + }); + } } } From 943d01959aeb3aa292b113d0a29410aaea24d99d Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sun, 13 Aug 2023 17:18:40 +0200 Subject: [PATCH 13/41] add `--min-size` --- src/subcommand/paths_main.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index 5df01ca49..76595b8e4 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -48,6 +48,7 @@ int main_paths(int argc, char** argv) { {'p', "delim-pos"}); args::ValueFlag non_reference_nodes(path_investigation_opts, "FILE", "Print to stdout IDs of nodes that are not in the paths listed (by line) in *FILE*.", {"non-reference-nodes"}); args::ValueFlag non_reference_ranges(path_investigation_opts, "FILE", "Print to stdout (in BED format) path ranges that are not in the paths listed (by line) in *FILE*.", {"non-reference-ranges"}); + args::ValueFlag min_size(path_investigation_opts, "N", "Minimum size (in bps) of nodes (with --non-reference-nodes) or ranges (with --non-reference-ranges).", {"min-size"}); args::Group path_modification_opts(parser, "[ Path Modification Options ]"); args::ValueFlag keep_paths_file(path_modification_opts, "FILE", "Keep paths listed (by line) in *FILE*.", {'K', "keep-paths"}); args::ValueFlag drop_paths_file(path_modification_opts, "FILE", "Drop paths listed (by line) in *FILE*.", {'X', "drop-paths"}); @@ -95,7 +96,7 @@ int main_paths(int argc, char** argv) { } if (non_reference_nodes && non_reference_ranges) { - std::cerr << "[odgi::paths] error: specify --non-reference-nodes or non-reference-ranges, not both." << std::endl; + std::cerr << "[odgi::paths] error: specify --non-reference-nodes or --non-reference-ranges, not both." << std::endl; return 1; } @@ -358,6 +359,8 @@ int main_paths(int argc, char** argv) { (non_reference_nodes && !args::get(non_reference_nodes).empty()) || (non_reference_ranges && !args::get(non_reference_ranges).empty()) ) { + const uint64_t min_size_in_bp = min_size ? args::get(min_size) : 0; + // Check if the node IDs are compacted const uint64_t shift = graph.min_node_id(); if (graph.max_node_id() - shift >= graph.get_node_count()){ @@ -387,8 +390,10 @@ int main_paths(int argc, char** argv) { // Set non-reference nodes atomicbitvector::atomic_bv_t non_reference_nodes(graph.get_node_count()); - for(uint64_t i = 0; i < non_reference_nodes.size(); i++) { - non_reference_nodes.set(i); + for(uint64_t x = 0; x < non_reference_nodes.size(); ++x) { + if (min_size_in_bp == 0 || graph.get_length(graph.get_handle(x + shift)) >= min_size_in_bp) { + non_reference_nodes.set(x); + } } #pragma omp parallel for schedule(dynamic,1) for (auto &path : reference_paths) { @@ -454,7 +459,7 @@ int main_paths(int argc, char** argv) { const uint64_t index = graph.get_id(handle) - shift; if (reference_nodes.test(index)) { // Emit the previous non reference range, if any - if (end > start) { + if (end > start && (end - start) >= min_size_in_bp) { #pragma omp critical (cout) std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << std::endl; } From bc8e268ab8aa86714ba8ba6a5583e5a449833575 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sun, 13 Aug 2023 21:36:50 +0200 Subject: [PATCH 14/41] add `--show-step-ranges` to show steps of non-ref ranges --- src/subcommand/paths_main.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index 76595b8e4..a8e0aa86c 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -49,6 +49,7 @@ int main_paths(int argc, char** argv) { args::ValueFlag non_reference_nodes(path_investigation_opts, "FILE", "Print to stdout IDs of nodes that are not in the paths listed (by line) in *FILE*.", {"non-reference-nodes"}); args::ValueFlag non_reference_ranges(path_investigation_opts, "FILE", "Print to stdout (in BED format) path ranges that are not in the paths listed (by line) in *FILE*.", {"non-reference-ranges"}); args::ValueFlag min_size(path_investigation_opts, "N", "Minimum size (in bps) of nodes (with --non-reference-nodes) or ranges (with --non-reference-ranges).", {"min-size"}); + args::Flag show_step_ranges(path_investigation_opts, "N", "Show steps (that is, node IDs and strands) of --non-reference-ranges.", {"show-step-ranges"}); args::Group path_modification_opts(parser, "[ Path Modification Options ]"); args::ValueFlag keep_paths_file(path_modification_opts, "FILE", "Keep paths listed (by line) in *FILE*.", {'K', "keep-paths"}); args::ValueFlag drop_paths_file(path_modification_opts, "FILE", "Drop paths listed (by line) in *FILE*.", {'X', "drop-paths"}); @@ -426,6 +427,8 @@ int main_paths(int argc, char** argv) { } else { // Emit non-reference ranges + const bool _show_step_ranges = args::get(show_step_ranges); + // Set the reference nodes atomicbitvector::atomic_bv_t reference_nodes(graph.get_node_count()); #pragma omp parallel for schedule(dynamic,1) @@ -450,24 +453,45 @@ int main_paths(int argc, char** argv) { }), non_reference_paths.end()); // Traverse non reference paths to emit non-reference ranges - std::cout << "#path.name\tstart\tend" << std::endl; + if (_show_step_ranges) { + std::cout << "#path.name\tstart\tend\tsteps" << std::endl; + } else { + std::cout << "#path.name\tstart\tend" << std::endl; + } #pragma omp parallel for schedule(dynamic, 1) for (auto& path : non_reference_paths) { uint64_t start = 0, end = 0; + std::vector step_range; graph.for_each_step_in_path(path, [&](const step_handle_t& step) { const handle_t handle = graph.get_handle_of_step(step); const uint64_t index = graph.get_id(handle) - shift; if (reference_nodes.test(index)) { // Emit the previous non reference range, if any if (end > start && (end - start) >= min_size_in_bp) { - #pragma omp critical (cout) - std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << std::endl; + if (_show_step_ranges) { + std::string step_range_str = ""; + for (auto& step : step_range) { + const handle_t handle = graph.get_handle_of_step(step); + step_range_str += std::to_string(graph.get_id(handle)) + (graph.get_is_reverse(handle) ? "-" : "+") + ","; + } + #pragma omp critical (cout) + std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << "\t" << step_range_str.substr(0, step_range_str.size() - 1) << std::endl; // trim the trailing comma from step_range + } else { + #pragma omp critical (cout) + std::cout << graph.get_path_name(path) << "\t" << start << "\t" << end << std::endl; + } } end += graph.get_length(handle); start = end; + if (_show_step_ranges) { + step_range.clear(); + } } else { end += graph.get_length(handle); } + if (_show_step_ranges) { + step_range.push_back(step); + } }); } } From ff4c5c95c69a99305f656852d17dfab0f005acd1 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Tue, 22 Aug 2023 15:06:02 +0200 Subject: [PATCH 15/41] check there are no duplicated path ranges --- src/algorithms/subgraph/extract.cpp | 7 ++-- src/subcommand/extract_main.cpp | 54 ++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/algorithms/subgraph/extract.cpp b/src/algorithms/subgraph/extract.cpp index c570068f8..2818f6aef 100644 --- a/src/algorithms/subgraph/extract.cpp +++ b/src/algorithms/subgraph/extract.cpp @@ -53,9 +53,10 @@ namespace odgi { } path_handle_t create_subpath(graph_t &subgraph, const string &subpath_name, const bool is_circular) { - if (subgraph.has_path(subpath_name)) { - subgraph.destroy_path(subgraph.get_path_handle(subpath_name)); - } + // The function assumes that every path is new and unique + // if (subgraph.has_path(subpath_name)) { + // subgraph.destroy_path(subgraph.get_path_handle(subpath_name)); + // } return subgraph.create_path_handle(subpath_name, is_circular); }; diff --git a/src/subcommand/extract_main.cpp b/src/subcommand/extract_main.cpp index 9a7da9a5b..a81829f0d 100644 --- a/src/subcommand/extract_main.cpp +++ b/src/subcommand/extract_main.cpp @@ -267,25 +267,46 @@ namespace odgi { std::vector input_path_ranges; - // handle targets from BED - if (_path_bed_file && !args::get(_path_bed_file).empty()) { - std::ifstream bed_in(args::get(_path_bed_file)); - std::string line; - while (std::getline(bed_in, line)) { - add_bed_range(input_path_ranges, graph, line); + { + // handle targets from BED + if (_path_bed_file && !args::get(_path_bed_file).empty()) { + std::ifstream bed_in(args::get(_path_bed_file)); + std::string line; + while (std::getline(bed_in, line)) { + add_bed_range(input_path_ranges, graph, line); + } } - } - // handle targets from command line - if (_path_range) { - Region region; - parse_region(args::get(_path_range), region); + // handle targets from command line + if (_path_range) { + Region region; + parse_region(args::get(_path_range), region); - // no coordinates given, we do whole thing (0,-1) - if (region.start < 0 || region.end < 0) { - add_bed_range(input_path_ranges, graph, region.seq); - } else { - add_bed_range(input_path_ranges, graph, region.seq + "\t" + std::to_string(region.start) + "\t" + std::to_string(region.end)); + // no coordinates given, we do whole thing (0,-1) + if (region.start < 0 || region.end < 0) { + add_bed_range(input_path_ranges, graph, region.seq); + } else { + add_bed_range(input_path_ranges, graph, region.seq + "\t" + std::to_string(region.start) + "\t" + std::to_string(region.end)); + } + } + + // Check duplicates + std::vector copy_ranges = input_path_ranges; // Create a copy of the vector to avoid sorting the original one + + auto compare_path_range = [](const path_range_t& a, const path_range_t& b) -> bool { + if (a.begin.path != b.begin.path) return a.begin.path < b.begin.path; + if (a.begin.offset != b.begin.offset) return a.begin.offset < b.begin.offset; + if (a.end.path != b.end.path) return a.end.path < b.end.path; + return a.end.offset < b.end.offset; + }; // Lambda function to compare two path_range_t objects + + std::sort(copy_ranges.begin(), copy_ranges.end(), compare_path_range); // Sort the copied vector using the lambda function + + for (size_t i = 1; i < copy_ranges.size(); i++) { + if (!compare_path_range(copy_ranges[i-1], copy_ranges[i])) { + std::cerr << "[odgi::extract] error: " << graph.get_path_name(copy_ranges[i].begin.path) << ":" << copy_ranges[i].begin.offset << "-" << copy_ranges[i].end.offset << " is a duplicated path range" << std::endl; + return 1; + } } } @@ -610,6 +631,7 @@ namespace odgi { const std::string path_name = source.get_path_name(path_range.begin.path); subpaths_from_path_ranges.push_back( + // The function assumes that every path is new and unique odgi::algorithms::create_subpath( subgraph, odgi::algorithms::make_path_name(path_name, path_range.begin.offset, path_range.end.offset), From b57665e807fb1157e028f2b449e48cb55ff6d9ab Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sat, 9 Sep 2023 12:57:48 +0200 Subject: [PATCH 16/41] fix typo --- src/subcommand/extract_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/subcommand/extract_main.cpp b/src/subcommand/extract_main.cpp index a81829f0d..49d118e92 100644 --- a/src/subcommand/extract_main.cpp +++ b/src/subcommand/extract_main.cpp @@ -118,7 +118,7 @@ namespace odgi { return 1; } - if ((!_max_dist_subpaths || args::get(_max_dist_subpaths) == 0) && _num_iterations) { + if ((_max_dist_subpaths && args::get(_max_dist_subpaths) == 0) && _num_iterations) { std::cerr << "[odgi::extract] error: specified -e/--max-merging-iterations without specifying -d/--max-distance-subpaths greater than 0." << std::endl; return 1; } From 938b2b72a11f908ab852993c41324ed0512394b6 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sat, 9 Sep 2023 14:35:42 +0200 Subject: [PATCH 17/41] a bit more aggressive sub path merging by default --- src/subcommand/extract_main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/subcommand/extract_main.cpp b/src/subcommand/extract_main.cpp index 49d118e92..e4cc7657a 100644 --- a/src/subcommand/extract_main.cpp +++ b/src/subcommand/extract_main.cpp @@ -35,11 +35,11 @@ namespace odgi { args::ValueFlag _max_dist_subpaths(extract_opts, "N", "Maximum distance between subpaths allowed for merging them. " "It reduces the fragmentation of unspecified paths in the input path ranges. " - "Set 0 to disable it [default: 100000].", + "Set 0 to disable it [default: 300000].", {'d', "max-distance-subpaths"}); args::ValueFlag _num_iterations(extract_opts, "N", "Maximum number of iterations in attempting to merge close subpaths. " - "It stops early if during an iteration no subpaths were merged [default: 3].", + "It stops early if during an iteration no subpaths were merged [default: 6].", {'e', "max-merging-iterations"}); args::Flag _split_subgraphs(extract_opts, "split_subgraphs", "Instead of writing the target subgraphs into a single graph, " @@ -134,8 +134,8 @@ namespace odgi { return 1; } - const uint64_t max_dist_subpaths = _max_dist_subpaths && args::get(_max_dist_subpaths) >= 0 ? args::get(_max_dist_subpaths) : 100000; - const uint64_t num_iterations = _num_iterations && args::get(_num_iterations) > 0 ? args::get(_num_iterations) : 3; + const uint64_t max_dist_subpaths = _max_dist_subpaths && args::get(_max_dist_subpaths) >= 0 ? args::get(_max_dist_subpaths) : 300000; + const uint64_t num_iterations = _num_iterations && args::get(_num_iterations) > 0 ? args::get(_num_iterations) : 6; if (_split_subgraphs) { if (og_out_file) { From 5571856a6cdecc7d83eb784ec86f2cdfdb1d23ab Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Sat, 23 Sep 2023 16:45:04 +0200 Subject: [PATCH 18/41] manage path range boundaries --- src/subcommand/extract_main.cpp | 36 ++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/subcommand/extract_main.cpp b/src/subcommand/extract_main.cpp index e4cc7657a..ce0ecc022 100644 --- a/src/subcommand/extract_main.cpp +++ b/src/subcommand/extract_main.cpp @@ -477,11 +477,37 @@ namespace odgi { if (show_progress) { progress->increment(1); } - algorithms::for_handle_in_path_range( - source, path_handle, path_range.begin.offset, path_range.end.offset, - [&](const handle_t& handle) { - keep_bv.set(source.get_id(handle) - shift); - }); + + // The extraction does not cut nodes, so the input path ranges have to be + // extended if their ranges (start, end) fall in the middle of the nodes. + bool first = true; + uint64_t new_start = 0; + uint64_t new_end = 0; + + const uint64_t start = path_range.begin.offset; + const uint64_t end = path_range.end.offset; + + uint64_t walked = 0; + const auto path_end = source.path_end(path_handle); + for (step_handle_t cur_step = source.path_begin(path_handle); + cur_step != path_end && walked < end; cur_step = source.get_next_step(cur_step)) { + const handle_t cur_handle = source.get_handle_of_step(cur_step); + walked += source.get_length(cur_handle); + if (walked > start) { + keep_bv.set(source.get_id(cur_handle) - shift); + + if (first) { + first = false; + new_start = walked - source.get_length(cur_handle); + } + } + } + new_end = walked; + + // Extend path range to entirely include the first and the last node of the range. + // Thi is important to path names with the correct path ranges. + path_range.begin.offset = new_start; + path_range.end.offset = new_end; } if (!pangenomic_ranges.empty()) { uint64_t pos = 0; From 2e662f80513d0257f8a17eaef3504182daeea229 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Tue, 24 Oct 2023 14:15:40 -0500 Subject: [PATCH 19/41] fix odgi pav seg fault --- src/subcommand/pav_main.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/subcommand/pav_main.cpp b/src/subcommand/pav_main.cpp index 08a00ef7c..b8eeffbe2 100644 --- a/src/subcommand/pav_main.cpp +++ b/src/subcommand/pav_main.cpp @@ -259,8 +259,9 @@ int main_pav(int argc, char **argv) { operation_progress->increment(1); } } - operation_progress->finish(); - + if (show_progress) { + operation_progress->finish(); + } const bool emit_matrix_else_table = args::get(_matrix_output); // Emit the PAV matrix @@ -406,8 +407,9 @@ int main_pav(int argc, char **argv) { operation_progress->increment(1); } } - operation_progress->finish(); - + if (show_progress) { + operation_progress->finish(); + } return 0; } From d5f5299692975dae5eb78a2cf6b60ebdcf3ebb5f Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Wed, 25 Oct 2023 19:27:49 -0500 Subject: [PATCH 20/41] fix seg faul on extracted graphs --- src/subcommand/paths_main.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index a8e0aa86c..410d9eecf 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -115,6 +115,23 @@ int main_paths(int argc, char** argv) { } } + const uint64_t shift = graph.min_node_id(); + std::cerr << "graph.min_node_id() " << graph.min_node_id() << std::endl; + std::cerr << "graph.max_node_id() " << graph.max_node_id() << std::endl; + std::cerr << "graph.get_node_count() " << graph.get_node_count() << std::endl; + std::cerr << "graph.max_node_id() - shift " << (graph.max_node_id() - shift) << std::endl; + if ( + args::get(haplo_matrix) || + (non_reference_nodes && !args::get(non_reference_nodes).empty()) || + (non_reference_ranges && !args::get(non_reference_ranges).empty()) + ) { + // Check if the node IDs are compacted + if (graph.max_node_id() - shift >= graph.get_node_count()){ + std::cerr << "[odgi::paths] error: the node IDs are not compacted. Please run 'odgi sort' using -O, --optimize to optimize the graph." << std::endl; + exit(1); + } + } + if (list_path_start_end && list_names) { std::vector paths; graph.for_each_path_handle([&](const path_handle_t& p) { @@ -204,13 +221,18 @@ int main_paths(int argc, char** argv) { uint64_t path_length = 0; uint64_t path_step_count = 0; std::vector row(graph.get_node_count()); + // Initialize first to avoid possible bugs later + for (uint32_t i = 0; i < graph.get_node_count(); ++i) { + row[i] = 0; + } + graph.for_each_step_in_path( p, [&](const step_handle_t& s) { const handle_t& h = graph.get_handle_of_step(s); path_length += graph.get_length(h); ++path_step_count; - row[graph.get_id(h)-1]++; + row[graph.get_id(h)-shift]++; }); if (delim) { std::cout << group_name << "\t"; @@ -220,7 +242,7 @@ int main_paths(int argc, char** argv) { << path_step_count; if (node_length_scale) { for (uint64_t i = 0; i < row.size(); ++i) { - std::cout << "\t" << row[i] * graph.get_length(graph.get_handle(i+1)); + std::cout << "\t" << row[i] * graph.get_length(graph.get_handle(i+shift)); } } else { for (uint64_t i = 0; i < row.size(); ++i) { @@ -361,13 +383,6 @@ int main_paths(int argc, char** argv) { (non_reference_ranges && !args::get(non_reference_ranges).empty()) ) { const uint64_t min_size_in_bp = min_size ? args::get(min_size) : 0; - - // Check if the node IDs are compacted - const uint64_t shift = graph.min_node_id(); - if (graph.max_node_id() - shift >= graph.get_node_count()){ - std::cerr << "[odgi::paths] error: the node IDs are not compacted. Please run 'odgi sort' using -O, --optimize to optimize the graph." << std::endl; - exit(1); - } // Read paths to use as reference paths std::vector reference_paths; From 142b4e79d597ce959c013451db2d43bc0c3907aa Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Wed, 25 Oct 2023 19:29:38 -0500 Subject: [PATCH 21/41] remove debugging code --- src/subcommand/paths_main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index 410d9eecf..c33904ee8 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -116,10 +116,6 @@ int main_paths(int argc, char** argv) { } const uint64_t shift = graph.min_node_id(); - std::cerr << "graph.min_node_id() " << graph.min_node_id() << std::endl; - std::cerr << "graph.max_node_id() " << graph.max_node_id() << std::endl; - std::cerr << "graph.get_node_count() " << graph.get_node_count() << std::endl; - std::cerr << "graph.max_node_id() - shift " << (graph.max_node_id() - shift) << std::endl; if ( args::get(haplo_matrix) || (non_reference_nodes && !args::get(non_reference_nodes).empty()) || From e5cebffdb119d72f17b7690fef8780a9a6324962 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Tue, 7 Nov 2023 08:26:10 -0600 Subject: [PATCH 22/41] fix odgi crush description --- docs/rst/commands/odgi_crush.rst | 2 +- src/subcommand/crush_main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rst/commands/odgi_crush.rst b/docs/rst/commands/odgi_crush.rst index ef61a54cf..d70a9b8a4 100644 --- a/docs/rst/commands/odgi_crush.rst +++ b/docs/rst/commands/odgi_crush.rst @@ -15,7 +15,7 @@ SYNOPSIS DESCRIPTION =========== -Divide nodes into smaller pieces preserving node topology and order. +Replaces runs of Ns with single Ns (for example, ANNNT becomes ANT). OPTIONS ======= diff --git a/src/subcommand/crush_main.cpp b/src/subcommand/crush_main.cpp index cd61a31a2..5f3149f59 100644 --- a/src/subcommand/crush_main.cpp +++ b/src/subcommand/crush_main.cpp @@ -19,7 +19,7 @@ int main_crush(int argc, char **argv) { argv[0] = (char *) prog_name.c_str(); --argc; - args::ArgumentParser parser("Divide nodes into smaller pieces preserving node topology and order."); + args::ArgumentParser parser("Replaces runs of Ns with single Ns (for example, ANNNT becomes ANT)."); args::Group mandatory_opts(parser, "[ MANDATORY ARGUMENTS ]"); args::ValueFlag og_in_file(mandatory_opts, "FILE", "Load the succinct variation graph in ODGI format from this *FILE*. The file name usually ends with *.og*. It also accepts GFAv1, but the on-the-fly conversion to the ODGI format requires additional time!", {'i', "idx"}); args::ValueFlag og_out_file(mandatory_opts, "FILE", "Write the N-crushed succinct variation graph in ODGI format to *FILE*. A file ending of *.og* is recommended.", From 4cc436777b4251f870b4be773dde4fac55d99fcd Mon Sep 17 00:00:00 2001 From: Erik Garrison Date: Wed, 25 Oct 2023 20:59:55 -0500 Subject: [PATCH 23/41] add nix build scripts --- default.nix | 5 +++++ odgi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 default.nix create mode 100644 odgi.nix diff --git a/default.nix b/default.nix new file mode 100644 index 000000000..91b82fa8a --- /dev/null +++ b/default.nix @@ -0,0 +1,5 @@ +{ pkgs ? import {} }: + +pkgs.callPackage ./odgi.nix { + inherit (pkgs) stdenv fetchFromGitHub cmake jemalloc pkgconfig python3 gcc zlib htslib gsl; +} diff --git a/odgi.nix b/odgi.nix new file mode 100644 index 000000000..f3dc49a20 --- /dev/null +++ b/odgi.nix @@ -0,0 +1,40 @@ +{ lib, stdenv, fetchFromGitHub, cmake, jemalloc, python3, pkgconfig, gcc, git, zlib, htslib, gsl }: + +stdenv.mkDerivation rec { + pname = "odgi"; + version = "0.8.3"; + + src = fetchFromGitHub { + owner = "pangenome"; + repo = "odgi"; + rev = "86e62bac42d737808a83bb00a0e7a60069494dcf"; + sha256 = "sha256-IKHQyP3E01LZvui6ykUiWPr2zuD2iqq55ARG+O2KCxM="; + fetchSubmodules = true; + }; + + nativeBuildInputs = [ cmake pkgconfig ]; + + buildInputs = [ + jemalloc + gcc + zlib + htslib + gsl + python3 + ]; + + postPatch = '' + mkdir -p include + echo "#define ODGI_GIT_VERSION \"${version}\"" > include/odgi_git_version.hpp + ''; + + makeFlags = [ "CC=${gcc}/bin/gcc" ]; + + meta = with lib; { + description = "odgi optimized dynamic sequence graph implementation"; + homepage = "https://github.com/pangenome/odgi"; + license = licenses.mit; + platforms = platforms.linux; + maintainers = [ maintainers.yourNameHere ]; # Replace with your name + }; +} From 82e0dcb3c2de3da3d9b5dc6d5c2f567cfa1eb023 Mon Sep 17 00:00:00 2001 From: Erik Garrison Date: Wed, 25 Oct 2023 21:01:49 -0500 Subject: [PATCH 24/41] document nix build --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 945f6bd49..d8789239b 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,14 @@ Static builds are unlikely to be supported on OSX, and require appropriate stati For more information on optimisations, debugging and GNU Guix builds, see [INSTALL.md](./INSTALL.md) and [CMakeLists.txt](./CMakeLists.txt). +### Nix build + +If you have `nix`, build and installation in your profile are as simple as: + +``` +nix-build && nix-env -i ./result +``` + #### Notes for distribution If you need to avoid machine-specific optimizations, use the `CMAKE_BUILD_TYPE=Generic` build type: From 0682d1d04c53221a5fe7f251e1531eb9f57a56e2 Mon Sep 17 00:00:00 2001 From: "Dr. K.D. Murray" Date: Sat, 18 Nov 2023 09:00:58 +0100 Subject: [PATCH 25/41] depth: option to use unique window depths --- src/subcommand/depth_main.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/subcommand/depth_main.cpp b/src/subcommand/depth_main.cpp index dbe33e62b..558175a7e 100644 --- a/src/subcommand/depth_main.cpp +++ b/src/subcommand/depth_main.cpp @@ -80,6 +80,10 @@ namespace odgi { "merging regions not separated by more than LEN bp." " When TIPS=1, retain only tips.", {'W', "windows-out"}); + args::Flag window_unique_depth(depth_opts, "window-unique-depth", + "For --window-in and --window-out, count UNIQUE depth, not total node depth", + {'U', "window-unique-depth"}); + args::Group threading_opts(parser, "[ Threading ] "); args::ValueFlag _num_threads(threading_opts, "N", "Number of threads to use in parallel operations.", {'t', "threads"}); @@ -437,7 +441,11 @@ namespace odgi { graph.for_each_handle( [&](const handle_t& h) { auto id = graph.get_id(h); - depths[id - shift] = get_graph_node_depth(graph, id, paths_to_consider).first; + if (window_unique_depth) { + depths[id - shift] = get_graph_node_depth(graph, id, paths_to_consider).second; // Unique depth + } else { + depths[id - shift] = get_graph_node_depth(graph, id, paths_to_consider).first; // Total depth + } }, true); auto in_bounds = From a9a0233f56c7ae341a0a3e040dd918a4d3b48f6a Mon Sep 17 00:00:00 2001 From: Erik Garrison Date: Wed, 29 Nov 2023 15:39:37 -0600 Subject: [PATCH 26/41] make svg drawing work with colors --- src/algorithms/atomic_image.cpp | 19 +++++++++++++++++++ src/algorithms/atomic_image.hpp | 4 ++++ src/algorithms/draw.cpp | 15 +++++++++++---- src/algorithms/draw.hpp | 4 +++- src/subcommand/draw_main.cpp | 6 +++--- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/algorithms/atomic_image.cpp b/src/algorithms/atomic_image.cpp index 7f0a836b8..870e2759e 100644 --- a/src/algorithms/atomic_image.cpp +++ b/src/algorithms/atomic_image.cpp @@ -84,6 +84,25 @@ color_t mix(const color_t& a, const color_t& b, const double& f) { return out; } +std::string to_hex(const color_t& c) { + std::stringstream ss; + ss << "#"; + ss << std::hex << std::setfill('0') << std::setw(2) << (int)c.c.r; + ss << std::hex << std::setfill('0') << std::setw(2) << (int)c.c.g; + ss << std::hex << std::setfill('0') << std::setw(2) << (int)c.c.b; + return ss.str(); +} + +std::string to_rgba(const color_t& c) { + std::stringstream ss; + ss << "rgba("; + ss << (int)c.c.r << ","; + ss << (int)c.c.g << ","; + ss << (int)c.c.b << ","; + ss << (int)c.c.a << ")"; + return ss.str(); +} + // helpers double u_ipart(double x) { return std::floor(x); } diff --git a/src/algorithms/atomic_image.hpp b/src/algorithms/atomic_image.hpp index a9b380397..05472902f 100644 --- a/src/algorithms/atomic_image.hpp +++ b/src/algorithms/atomic_image.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "picosha2.h" namespace odgi { @@ -92,6 +93,9 @@ color_t darkest(const color_t& a, const color_t& b); color_t layer(const color_t& a, const color_t& b, const double& f); color_t mix(const color_t& a, const color_t& b, const double& f); +std::string to_hex(const color_t& c); +std::string to_rgba(const color_t& c); + const color_t COLOR_BLACK = { 0xff000000 }; const color_t COLOR_LIGHTGRAY = { 0xffD3D3D3 }; const color_t COLOR_WHITE = { 0xffffffff }; diff --git a/src/algorithms/draw.cpp b/src/algorithms/draw.cpp index 7d86d3b75..7d606c8f2 100644 --- a/src/algorithms/draw.cpp +++ b/src/algorithms/draw.cpp @@ -104,7 +104,9 @@ void draw_svg(std::ostream &out, const std::vector &Y, const PathHandleGraph &graph, const double& scale, - const double& border) { + const double& border, + const double& line_width, + std::vector& node_id_to_color) { std::vector> weak_components; coord_range_2d_t rendered_range; @@ -124,9 +126,10 @@ void draw_svg(std::ostream &out, << "viewBox=\"" << viewbox_x1 << " " << viewbox_y1 << " " << width << " " << height << "\"" << " xmlns=\"http://www.w3.org/2000/svg\">" - << "" + // interferes with the styling of the lines + //<< "" << std::endl; auto range_itr = component_ranges.begin(); @@ -134,8 +137,10 @@ void draw_svg(std::ostream &out, auto& range = *range_itr++; auto& x_off = range.x_offset; auto& y_off = range.y_offset; + //const algorithms::color_t node_color = !node_id_to_color.empty() ? node_id_to_color[graph.get_id(handle)] : COLOR_BLACK; for (auto& handle : component) { uint64_t a = 2 * number_bool_packing::unpack_number(handle); + algorithms::color_t color = node_id_to_color.empty() ? COLOR_BLACK : node_id_to_color[graph.get_id(handle)]; out << "" << std::endl; diff --git a/src/algorithms/draw.hpp b/src/algorithms/draw.hpp index 8a1f1be50..6315e90f9 100644 --- a/src/algorithms/draw.hpp +++ b/src/algorithms/draw.hpp @@ -69,7 +69,9 @@ void draw_svg(std::ostream &out, const std::vector &Y, const PathHandleGraph &graph, const double& scale, - const double& border); + const double& border, + const double& line_width, + std::vector& node_id_to_color); std::vector rasterize(const std::vector &X, const std::vector &Y, diff --git a/src/subcommand/draw_main.cpp b/src/subcommand/draw_main.cpp index 12edf2e60..620e69d21 100644 --- a/src/subcommand/draw_main.cpp +++ b/src/subcommand/draw_main.cpp @@ -41,7 +41,7 @@ int main_draw(int argc, char **argv) { args::ValueFlag png_height(visualizations_opts, "FILE", "Height of PNG rendering (default: 1000).", {'H', "png-height"}); args::ValueFlag png_border(visualizations_opts, "FILE", "Size of PNG border in bp (default: 10).", {'E', "png-border"}); args::Flag color_paths(visualizations_opts, "color-paths", "Color paths (in PNG output).", {'C', "color-paths"}); - args::ValueFlag render_scale(visualizations_opts, "N", "Image scaling (default 1.0).", {'R', "scale"}); + args::ValueFlag render_scale(visualizations_opts, "N", "Image scaling (default 0.001).", {'R', "scale"}); args::ValueFlag render_border(visualizations_opts, "N", "Image border (in approximate bp) (default 100.0).", {'B', "border"}); args::ValueFlag png_line_width(visualizations_opts, "N", "Line width (in approximate bp) (default 0.0).", {'w', "line-width"}); //args::ValueFlag png_line_overlay(parser, "N", "line width (in approximate bp) (default 10.0)", {'O', "line-overlay"}); @@ -174,7 +174,7 @@ int main_draw(int argc, char **argv) { const double _png_line_width = png_line_width ? args::get(png_line_width) : 0; const bool _color_paths = args::get(color_paths); const double _png_path_line_spacing = png_path_line_spacing ? args::get(png_path_line_spacing) : 0.0; - const double svg_scale = !render_scale ? 1.0 : args::get(render_scale); + const double svg_scale = !render_scale ? 0.01 : args::get(render_scale); size_t max_node_depth = 0; graph.for_each_handle( [&](const handle_t& h) { @@ -216,7 +216,7 @@ int main_draw(int argc, char **argv) { // todo could be done with callbacks std::vector X = layout.get_X(); std::vector Y = layout.get_Y(); - algorithms::draw_svg(f, X, Y, graph, svg_scale, border_bp); + algorithms::draw_svg(f, X, Y, graph, svg_scale, border_bp, _png_line_width, node_id_to_color); f.close(); } From c4484985e8707d0624ab99829691fe75ca8db52a Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Mon, 4 Dec 2023 12:54:59 -0600 Subject: [PATCH 27/41] update images --- docs/img/DRB1-3123.du.png | Bin 5031 -> 5032 bytes docs/img/DRB1-3123.png | Bin 3107 -> 3141 bytes docs/img/DRB1-3123.z.png | Bin 2221 -> 2290 bytes docs/img/LPA.b.png | Bin 2279 -> 2299 bytes docs/img/LPA.bm.VNTRs.png | Bin 7265 -> 3305 bytes docs/img/LPA.bm.png | Bin 3528 -> 2325 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/img/DRB1-3123.du.png b/docs/img/DRB1-3123.du.png index 5810380a984f110cbc9d1579e077b772b82e31f1..665eb81012029d92e39a8e041f28ba409f7eac0f 100644 GIT binary patch literal 5032 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 diff --git a/docs/img/DRB1-3123.png b/docs/img/DRB1-3123.png index 58bd8d6c2531dbe652361556a7db2a41dc11efff..48163fa7ae27b13e68b0d29d885e35b4f5bae5a5 100644 GIT binary patch literal 3141 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 H<@Ub-#^PhP literal 3107 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 C@Jc-Z diff --git a/docs/img/DRB1-3123.z.png b/docs/img/DRB1-3123.z.png index d90d157b95c29bf6c4f63959cc883d11bcfe61eb..7702cb6d77dabcd6d82b1b40a95ad34c42c425fa 100644 GIT binary patch delta 2271 zcmV<52q5>Z5%Lj`7Ye%q0{{R3O0k1;ks%m=q)9|URCodHm0fP*IueD+f%Gy@G9Yha zRv`mf00WTwxl5VHi(ciNQ&pt(=X59C6P2$;#S%%;&ZknbzVKUZ!l$53a^7u8S4yw9 zIecwg{!lFKX8T?j`o)^{FYD}puVy*Wvwq-NN6Q&o$=>1U1Aqe#w2)d)&Uy*@XEU*X zHYZWf2FzY2Ur6!{d5*3##?5;NqZdY9KqO&^hq(^uBhC?@96GrhY$oG=Mn4{m&PWTo z#!}IFWsEr*Jk zoL!)AYzpBFYE!zCb`_g)Ot)(7cYwZUQzFx*OrQ>$EI>kcJ0ikVYS8qdVcP@{$kBZ)K@l@B6+tb zGo5K=S#S4UpnqUft0^NssO#2eK}|l;w>AycriT8;r-4^{xK!=xBI-LfMPF@dWe_f9 zUGL%rhuGBx`kqar*;HrgQr!dbhNGBmk4OK=rWGAAC!TrL?mIyL(5AJ2!eHDgjNNyD ze%kbz+SDRnGPdsLqdv7awHM-LGCYp@#-@_n+03d(Xgi^k^)Ar&Y|6hnsdXl_iZgPR z5A;2oQuP&`4y8@C;?u2I`m{%R2rHY+gkDqs9_9 zZ;zwCv8m;@=KfIadOv11JrsS%rdmz^eX1Jn%Px$a5<2~U$pzqr> zi%qS%V0KtmnBXGU^K;kr7i)jv^8@X#@Z;|v;a@*?+JAMW^!{yg_}YJJudZu1XYKFB zKU?4317g;9YSfnZ;oj5x(sza~wI+;KO01lOR#>otb!U{mGjzho@J6GGm};5KvF9P) z<^4W5Lszeku@m)w@T@*fc!UcNO_%@tFF*rrcL-1v?-K~ja_zH(v{NdZ4O_% z)?QuLZqC{=1=e@hFwFB@vt6<}%toD+#_Cx|=u%x!JE|{#!@`~cHC{(jcA~qelTm!C zE=6s*kKW9+M9-ek)uf$VJNR@IpC%i@tWgtY#5l{NctJOl4qDrrPc@B-I##btD|tI! z&@Jkd08iDY5_ODdR^6t2L^G=!^cw9f(XBpBIx>f9EfAqtVT#&8N+#QVV6EHkG;P3BB6Xd@AT- zQ}lX$4z(#B5o15-)uv1pF(`al%%(YB@D_5lDbO)?gI;agu0`Ts)95BSQ<`mW{-RE6 zPSvMD6K2vKAQ@wi<}241HmyE2o3;w0HnkZy=)Yxu(__(Js@14VAj9L(TO1kKtc$PZ zr;UYf-hLMKg-s=+b*_Gbl~29v2z_N!(UbZ!MZMx|mc`i<`pTy0_i9r-l6sV9SXNw{ z{h)7biqA#RN1!udSQiGd?1;P34f@um_}uhO*sR!8EsLHX^sP+=I4QP$WSh!v=w>!O z9DQql(?M;@8U2Vntil9Gx&C#V9*+J}tww!%9Prdarct+7G%kM#Y1ps7*M)wuWu~-zqhZB#ar> zq*HlM=3~aG$Ke27t2yd4l7arrbR|Yf&JlBe1x}?~gU#f4!OZaqW9}5;h$}TG2CMU8 zO*oYfEjEKO4lhwB1`Vm`@;Ir@DI}tRjDFe3#p(bHf&?B{k!jPD8bzz4A`o4f-)9Lpz0PSDk=>eY_^v{DIlS{C>D zP(-I~xjH&QH>-+Qfp^o9$W`bONK*Qo0wh$*L*FrA{?gUCb3Jtydj%(O7O zTBS*1(ppzStv+&ff}WqduD?(#N4DR8Lm!YQ!+T2D;@5EsDaWaQzuoePZV54$)OWh_ zGNleXJzvU|`yRQ_k13>UNM*!moTixG%PsY>Oji`&G?rV4)8e09!~1)g`Z!(R@xQ_! zKsS}8{hu>*tO7dgQ<6bHG=WP4`uclujs9mcWs8pg{!8dKI2`@@b@X&})Wes5(Zh*; zqW=#1x=w!=`jx(K(*FedwSH&XelM2tT~Xiv@jH6Yz^>3++n{sxwC)3C;EwgqMzs|`iXv`pXew0iT)2kFY}g;W_}TL tpY23H(NA>uZCUq9c_Q?)o$b5Z{{Y(Wf|<&7)0O}L002ovPDHLkV1i_ynBf2b delta 2202 zcmV;L2xa&35v>uB7Ye!p0{{R3f$dP%ks%m=Ur9tkRCodHl~Hc%x)FxSLVoF!0?3=_ zDr6viR{?TAXDRpbAgk>E&kSixrkp0Zw;ErQiX@VvosZ+ueBnoJ#(B;;&mr%%MOR`~ z3a9JbY5hep&vE;?xLI`Ge6!AuF^41vde#rT>S#S|pfFs0)ZB4Dm2G0DZzW;!I(Xr@>|to+tFK$B_HUIjH=aS z!hy=p=Th^h=qTzdqe|^wD*GwC;|Sp$Jw_cPALuQk4wz+hGu;{A;t-KAxW36Rgi-X6 zFioTK8q}?57v{el7eQw)IzVq4bq4gJ!k4kVrnb#NdJfPVMwRQ*sxVT2+*Fu<^xSp* z#n9z{%6)FB`g8PaYoOmR+Cksg6r)j6iN$h|XTyzM_04dBes9x&m(<2Ir}(rQinRw< z7wC63g>Xi-DcwoCicLADTebE(KyTTU$h0XFXuxQqO=UcZQ74-AaP+24dDkfOEnuvf z{~Gm+v#76aDqGNu=4+}x4IATsIzVsORPKx22lHvztZ{&zp1ZDh^drzWHkBfIwI?&3 zX=Pb&&t0HDu&LFQ2`B2h^;u9CAL#cs4aKI0{?6UNt0%Zr?dl@x4V$8`HnlPcm$I%8 z@ePOA)dhOXrqOJwvvjGx1Mz|*n{AIre`M2wj+hhAylT%Kpg*)}sW2FS*9v3L9iVrc zJ`?(EymQE@_0K;=S2gUQ=XEmdqu<$7ayyw>^$7J%7-YQ*^p;KeS0=U2gj#VXuJVE2 zvME(x(CJXxR4YE+id7!a+cq7v3b#L(v;H)rzA2lv-osQf{K7sBdga;84(|)(2y^9VHLwZJTDXDZhcwX;s=Z*M3&SNQn-@#`NSjrNDG#H!!npVv9-{t?Q$)~A23{@M0v3y4`is8MU) zhigxtOWzr~)S56^DY0@AYGJ_&)}2ZE&d>=T!#j;CVk%`a#S;(lE}x%*Gj#Rp6bDfc zujqv!2k4SMi#PEvxXCYS2)gW7ZXV z@#=8vRos_qP^~qC%(_DVnpa(+hgU(T{%QX?lD~N z-NG=>Q^|J8>Toj}tTYzSIzpG~g4$7h8CLcTsPQ_IvJ>5ZMV*Y|Q*|k7%XRc_t|fZ% zgsvtXYX(?v(-P<5%+AwLQ8MU%3*K@TsAzSs89*IyLx&==(IdeQk4 z^peG9&}!3vaul16+gv{y-E3NYT5T$|PzGvKnTwv#i%rd^f-W{i@1*-sn_`O?`#~=@ zWvYll;md3`P4NxCLMk=|I>v6$i%si2OZ-b3T_k66we7`U)M?GR_%vw3%=!jM#@N<; z<@(B|#iwS|T4B_tHsc2UM>ahcJ-i}1;TvDRZfo>^{CPvh-nRS+`pTw~(K=VoVC7Sv zIzr#rRP?0&T%z7_HOu1a34LQz^iOJ2Y)L)JD=aInO@7etY>M+u&?lfXVJ4~TwCseZ z(GB{&O>tiIm#|r}sah62Kj`;172rj&?UdJ4-iG1EriY{7+jLZ$az;`ogy4@rRKzcXmwt!38&Jb*=8`t;U((Cpdl4qwzJeZ zg+$bK=Gu-%*QjgdP=E3OdYvnkCT!}<(FyYnhhCe53iE>K7r~~Z=hm06(FtFdEZcQk zbh4dx19Fef7dA^RDH+dn8jEGcvGr}h$PGGQ*F}Y76@*nLNQJivj?BDV=>}b+o&=qL z{*+n|@KG$wCcgnU$MT7h6LhtzdUc>btyBV?mc?^!is-a0S4Su4W>xVj@Gd%%9AQ?A zMT7ZPe-St6CF;5bG38tnW>9q7h-^ZhIYC!sriIznD$OD$Ep;W7>LYh2=;^uZ`U|1w zBij$7j@+-Io|{3sMm^OiVotjM{w(T$599P>biBZU)hNz$92-lKLE^g45M(Pl>+UI(kR%=<^O8H2_kSq2p`By01A7a3a&Z)IPyWEo4z7AXz&GJ`@d!YfO%mnDN_ zAIo@3$rh(X$TA^&1}O^78J%;kb6w}$|J?U=|Mj`Pzt8V?-*W=n0?9Imlr2qd2`m;% zZkP-J0M}xowi-*XA?`>K%~~NvUxfVESdSq9aNjv?WMCT#eolM#R9hY0p)=JR$%ika zh&km0Dz*AN&RTCFjXw6_&?SmUX{1BC|452P*N2RGNu@A)nBS|3upf@w@~ubdBflH- z&}D*|U*6%7FT#h6cG#xTB^5aFD(UJ005{szu)+^4Q^5*wGv%(iK3t7qaK z^dlU}U1@|%r4>;N9>m80-u|&Zt&HL2#F5kGha~oJ!s`q%+y+W_odJ~N9gLqs^|y}F zfZUQtEkCMBvZG5mvlwveVdOY9<73Y3c?5mwKz$+xtXvx;eR$cRbF-?&R)gkaw%Ls3 zKer79`FRBt0~UTQTGwj`+o8Un8UiCFR~_ z;9S~BU*@76GpAgY=ye2mbgxqRlwp8y!ft|Wh}A^bNkn=IRY{{t=~UiRAxi4!hdztm z?xBN=oE?joC>y2Q`*oHQ zn}$T$EiVF;u=aLG&LQOnq&FPTf}!6`amz5rzjMhjzUBFT&byjF#hJ68nud$e^84e% zU!=Dx6br8FPw2uEr`zNhWRn$-hn*4>$)vmq4H;x6UZ_@b>8M7bTzf_Lo#5+5Ibhyh z8vs#tm9ZVe^CWK*)h$*VTg{3JJ;C*zxmd8yh=~kp4`G1; zH!q_8;0+$!u?%@{`!gR9#xWo)bM>}|!>yQ61<|FEG;36RDb|q6P_w5xAj3&#(0jBUTqIUBgvdR3py9 z{4O1?Yr*uk%b2z}t{QLa0c+P@gP)2wHwx?boy9rDk(w@3iXvsRXT^iIFF5!oz7=1m z1E$Hzk)Yj@GMukeoLy&IKQLJVVi6$mZ<@5a68V={U(017wAHf^uS>$&v%YrJFNN84 zMs0Jzm>xNEHg->~?r14|<^zGhWdW9ON_gC(%CKDP72zj+y>oSgp(RVu*0p1lhUePj zn;bixF8-MB1TXRjwKFTYuuESY2zfj9-{uJcf+o7lIi(tmA=s%uwqSc{vV>4azNuaq zbzgW$%uXIH>kAfl`?pOyeF~qr(*zlFg2-I>b@>} ztT>&}Ig$odUGM4L?|zJdB+d)}*>k&9@GGbDk-EEXc){V5wKFF|`x>m?WT={~o4*rW zUC_5%q^_E8RDhEq`yO=k0Ia8E&mGsRv0a7_UX@w=2a`RsR(KQgw#y)V#aiKLz^_hl z&#_8-ZdoWowB)nts}vGWKqFB5A|E(D{FijOF7iN6CmOrv*3PRGpIoDeB!14gFZJ9K z=3!g6)ftTl@-h13u;kY9EAov0a`F83#+B);1LpDB7ST~m=SlHZmy9aU84NVEHg`@+ zqBr8?&0}o;YKynWQ@Gq5<4E19EF^|(U-LYSLv;Tjv(a``0;hkQAYw%kYVO>@JF%r( znW{EsI>b#hs1wU-ot~X$wf>r;gCVYdDhyt*omtS-Pbqrh9F?m(`sk31s^u4bE0%uW@drwZUaa&!9S;DM|al8FSK zZQYbPMR7*$8rhP=fO!xTOB(jvMD->i zGSqLpI^!-dtf0BjW-pv=8lT_P$0hDNtbGLo^6GpQO`@#g?_#V$2w0XSW ztU6=vPqLt}4%5xo8!qt#LKRyC$tG~pc*oI?oLdLnST%-^+GO4K^CN$bEu>1ertXlw z*<|{A$a2GIM;$|nCcXLa>8aski7B)F7qnr={9tv=CrFeZj6RW7O=6EZ3MyWyP+u`f zwW437pr9T_FMp#gf`V;*peRL}eoqZSW`HbRTKUBZZ2Ycb^HBF<*eY7|22wIC2$;3f zWnDzjbTqnLa|a}7Lgm}ay!F*s#(x%pWue6TC^*jt~<-ln4f@(?3%ZV-t zyqeab_c60|>%_+T{md2@z`k=)EO?g+_5|*cmPj$j4hD&oLequLz_b)2K8;*9`Nnpf zuD!>qI|o(3uWNPB?~R)+cI9!lBbNi&sb=Zf<-Iy#9MgyaPH92^nFB~TtSl=yQ& zcC2Y!?RFrOC-Z-Sy}z~|MCcyYOq)+!?c3f3^lnHt8(HqM+|8?k1zSA(Hq)$ literal 2279 zcmYk8dpuMBAIHyTn@gKTsWnP9ZpN^U!-T#FDAvkG0rrind=?dI%2jfYKNYO2z)R80#Q`aIBo5OPH9 z73d!UST9y{lPhekkYnsP6|W{mJ@M+m?51iZ_~xA_jSib1J>v{wy+@DmOQo}t4euqV zIY%{h6noa@r6+8ag_WC33QAJ|_7ilc#ThWcBb)tzFcAdHE7}KdQ#LJ~K{0B|B;CjI ziy4^z&{x9So?LP{bknmbmRQ*ZkV>gVf%?DYuW?{~vQnrFQD7uU(YV^=KS{p<2H2e4 zWuQ@Ui54(+UhgIi-W`GXN)1c9BO5$_x2r>;gPL3kTA;NUzN^+QAkAwBqVdKm;BhyrjCzl6 zDK=51QtZwF>}Z5I`;AbOTtP52dF~le(D!4;3p-~#upuh^z_b^va5A1U9dy>`9|rgQ zqkrZHeHA^jQXr$?_W8YnWle@;{ik0?(`e65jA2#}s|*db&pk8$S{)AcXs~%J zSZk-SHBj#;XXpPxa@K*o3{|Ob{MzqVK?zo}Z;TN2_ab@LP9MJoi=1e2%Dy}qE42PX zSArT&V*H5kC76a5xgx}B#}2O<98tf)rZprj`NAK7&vmM8_|x`H=KXP~AsKBQ7&2a< zkx?Q(KuZyYhX92(tI*a&n3JFMf}*0hHzVrf-)zshjr!?LvghtN;YSO~%S`4oW00r% zG5CZ*eO8hugiT>Si^R^)&d(foatGU;9KKgYME7wcf?Wv<8L9O~;sGel00;AqA>9&H z5ny>q7x>xMC=d6@?pbZ7;u$m?G%e}W!*H|Z3QeOcB?41JM{;=pGIVKdie&{48j?eW zh!#~3xjtG1HoC?>Y(1~&c{m^IwgcT*;oCePBH6}7EyR+LM8G=Tvcyke;YYB8#i==; zIr>WPN$tfeKd7>Dmd#MzJ`<=HQumVKqgbXMx0z+Gz;*fohJ9EAGLI@Md}G=-2g)TP zwg(pD))W_SNA4f3>$upw=|fx3YVJY7?H37@x$2WcRZ!J~!z;>I@nI zx=m*GS1Mry`naiJ17%`L^3=Z&X>Q#yzzomMLzXTFjGt&)N$7f_)UFP4blYt=y9}~< zl$lIF*5r@ju=>v9FgYT4zqxK?5V2q%pZmQL^9MrD`e%ef=dnONcxB;T|1Fx{qC%I3Y@{g_BV*WFho~d+nE_ zGeNpWpN#u8D$k$|X?e(z2&1g?4W(#k*vQN&#Q|EeH20mU4J*E)0<{I_=%iIcRsJFT;r3XEvt z=(2!cl`y;nwEXrAcTuFuV0P|7ui` z(CB!n&8wiPmkI;3Q@$GsT}f7~t%~0y<~P2NUQnb5WH8$apuxC#EXN12_f#LX*eOkO zeHE+t=YM&W&ppmfDTA|1CuQ3h(E4pvNpwRY2^$Pt| zyso>PFaK;63X4?2k)eRSkJOea$F#tytvulnz+8+TrLglP-!^Yc433;&7+AxTtfF$> zos}AYn*i+aB3+@Scx=1!9@C6;N=pHWYWd)>m#j_)OE7v^7o`VjMB{7iwk8)1p3QEt z{#aF)Y_=cpt!_?0;8s45A+?Rd6sZ0O)R45QtggXjdku|azMR{W=EC^>UwjU#_&MVd zB=HPbeJ@jI$>00(UYk+Mv*lF5W`0i8mXuAfY)@wv4w}S-Lf);wQn&rg1UINin#TxI z-JjoDRWBsvCOVKV;&b9B-(49OR`WiHj*kmhg6sITX{1mZi7pKyBsV%a5pFF)K4YZK-e_q zs6=^w|4V7_tfeNeL)iUAHWF^j^80j_4A|~~OWS7!00+UaZd4a%?2&)mP5~VD!?j7i z?AK!en<9Up1Msw#Us=!f*8w%q`<(X%3wV^Xv-88LR{CYFnvtPfDtYpM6~N8K%emZ< Gk^DbqVlKA; diff --git a/docs/img/LPA.bm.VNTRs.png b/docs/img/LPA.bm.VNTRs.png index 7549c7a4b70e9926861ffd402820b0b1af73f313..c2faa89322f6cd34cfb41d4db05959d9e0ac9e45 100644 GIT binary patch literal 3305 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 z zQfi$Ro^mrYO~b}l0BqQg^ke%&sRtf8Uz5OKJz)p-7N-pq?>=@t>5Q(R{bKi2!S$qB z06H5dG*5kD&@OyM%krt9Y8aMg0pDErFq(p)kDd6$QbG;EU5gtKz*L-C&ne z9fEy;QyZ!sW^5|$pe-7FvQ92PKXWJ45~>YX=t*=8Gig_qrp;jTI4i`1it2K=Eo zT=0Rm4p{Z2tOjk`|DYiU_!+R|u5RiXNUKKL!vtB;Rg{@?=)A(7rAM&dhAO=gFa7nE zC(iy%F>m7I1lG>+r{|e2q9pb+*L<6}n?YxwGz~7=D0ZUD7RfKv!mXjFBFPqp_YfP=wr&SzSAJP0 zNz)dc7m4ZZtG#+@0}Bk26PGK#L_2YI;O381Ig(P;%zR&iUH$g$+oyVO;j-{`qEvc5 zl-rycOn=Rp3p=L5w|ji+U!>OkLEsI`nV=BRz7sJ+z4(WeaS0=)XEL$Qg2Ix%tf^^D zIw!Z>mITLL_CvqKZ|E*9k;`oMdMlk~tQE_^nmrE>cl`BoF_rexu4ZelZCUV-gFpP$gmR1Bk%H+ zyU5W+c)C94!?8dgKOz*rJ%-^72jaBPFQw(kW_+Z}tx$!UlNxw@I}zv{YHyK)2!TpWQ^qd<<=?wMcAk_Moot|=snVXC)%nPunUMa>y2pU&3NWs&Up*R_}!9K`DpcrW_6vnb~a!GU#%YFTbqTzH9r0 zvMR&OcWopcyb2T11LTt7tvCEd?_1x~ve8gOZ>tu?EhB3_S;K!Cgd_2gZG{ab_CL`e BI|={* literal 3528 zcmZXXc{r5&`^WEjW`?mZ+0rq{mh4AG#u}1C$kIrbi6SLS)?}GU%PE!QWJ#7%*@`JC zTRfdor)^ZWk-@a!L?IGmH1nIObAA8${c~T>bA7JQ_1v$|`~AK@*K^X#!$nG5RU81M zT(>xR10bm2xqyHbRKroVRsami%iY(R&*$R^fD;3P9PI0X$TzUR7a|xC_a0(~A&Lpn zEFdKcHUS0!tSH0`!GX81zYmf=L-Zgd{0njKAgUkY$G|2P5Il%V!=|I)kOhv%z@7>& zXJAtnIGq4{8rY_R<8jb-1%fR2-vV+y?6?ivYhlMN2yO%adI-D+e$}w^E|`S^1`Ajb z5R-@GDM*0;}5FFSZ2I~~CO9!iXSnULc{$M}`!yRDY2PVN_NCtf$FxU<% zW*{m9zE$9J9kyKo-)bP&fmb04qdD5;5&X9*F5zVB1P;C)suq$`QRZv>oZhZ3Cgby zA&;2*^ZR5eDN_AZ z7QQ^eFmt#DUnZLPipG_>zVor7U~whe14(JaCg)1Kn+K^Gj*G{-mPk+?z0P4MbhVUb zFRELO1J$|wMOy!=Dyao!uWYCfI6GP7O_kV!2`*7!Bi>Yl zNb`QrJI#Jv9lzerFC}O8lUB9%TYQg>8fk0v%r~%*`riBSXzN>@i0?(CdxOhdD_tf| zc46>Mg{mSdFAD2!LC(ixMQKBS{mYzo!Z0f4Fs3h5tWzW5VdK9Kc;yV=e(6AO0WC~A z&}ec>icZ{`cRq-KDd;|(;Y$`Y>`aZ+NT7wBy2hkMUiXctF+g<^iJ+_LRfIETO1A~B zL3MgfQKcIU|9%-|)YZcdcY7*#)!&{I?upZZc*|B*T*~PC#bP78WsU;-4{z$+7EE2m z;6O%2J{ZqbB}-2Yb3Y6n&TPq?8RuqhT%H{HXZA}Au7Paf-c%cOFuZKX*|GVegw(60 z>{z@ad)Z}!q-mj9P#A_N(2LVjeOYbMSDX(2Q8lRLRhthqe^6k%?~|iAI?0Gjo~GNc zeoGD`llp%#MW}DVFs>?LuG3!OGek{yh5mx_5I2=D6{9`VrankwAG!<%sAh`D|A*3U zMQ#9DPLv&}j}~2p{#@jet9Y!DX1C`~JX^wGNU1xk!!GSx&WRj8=i}FI7f;^&H2>Ua zFSc!cTDLCC&tv%!T4z4aT=o}g#aXIglvP5+Hb=->=@$Pd#`?T+_-t3Me94TBKDx0- z7c~v@>XH3)*$0!PmfmDnMe1$Db`2@{NWiM{R8tB&%lV;d9ES3+5;ws%kDY(m;uC}^ zZ8f^C1OmKt`|C+;<2ORtk_EEG-|OsIjcSXO?*Wx4(O_c*cJpB9J_3b5HJ!F#Kc}W- zJ@M_K#^f+fbNSAc(*nbf+E9z3)@F~!@T$dQrS;Lqs}PZkq?OL!=-C;tQR#|t^mJ6< z-~jV}`>o_K?%2&AOERfWBZxq^ON%FIK@p5woLg(bu9?&-j0&_;6X0<38 z_=7&>JAL(c@mP^YFqJwwwQ#RmttmU{v8hiDX`m6S?3)dFD%AX+Sqm1}vPTx>4UOQ* z@iG^u>FjNl>LNQ9q$S@~CJGM8xLgG4>QaGmL7=CF5#AqTTxD%HHP$yV@_Hq**ufvP z86LFZ@u$9usuQQv6Joa$6KXTNOyAWVOunYo^xjj_ftXwJi2a*>o=0AKb)6u*ju1vj zNDD#=2ecw)yKcD)JJ3amEx~6GpyrsQlC&oEaL@C};;{~mK*!XGVnqliM3F7W3|hN3 zluMLLThVJfs){Eu0M63h;BLD$N+Hc0 z)cjft-bO3ePJpBp>ot^!-qn>y)=VQAo+^3SgA;Ha*p zc0cI~X-k`bKdRSN*0J=hp{rx@yrH_^kDd*lBkKejvVuMl>K0cxo^#o)XJ+a0>}vP! zk;1%jA8P+^l$4Z}ULPjq(HF#x=9jjLEv1Rmk*Fs`Rbt>>Oc#!sIQuT6&?b*nI-Da+ z?A@QZI2+ZH{)r{ViM=6>|HCEq9;RMaOS!xrUntTxtn{f)%m37&b$NXy6H_7dL4s2^q*PNWR}5oPHoIdq>wYWS@aIMiqBj`+_6eVvLCN3OK&$b z%j?^kh-bQDr0X)gWaU0shzYL=fpzyw(=!(aFWV)l>||>TeLLQMw48Cf4(j#L-qEH~ zeSu%20|bZ8y7O$=qZnVc=Gq&uv(kbP!Z7Jq{z`bef?8(3X#cx0RJUYoGN;9+{zc9; zxQ7U)Cn1`}0(NejX`UTP$Le`pk-8fuT9$${O)XK#C0Z#`7DbP9l}l`2H)2UQ^@UlK z^w<7H^K;Uu{KQeDR0?G?l-KyjnWJ_iG*swPae5x|Ti}m!jn$81L7i1>833N@-cnbm;XjxVx6a3R+sISy->Aspy{XVv|qVq+*l7-6Z(|{VAMQ z*vk+C>xdMs^$MzeEK1Rm{HgNn#SYmfd=|p(Q{OcEV%&K*GB^J%?@znG*70Adj2=T9 z!tB|d)r>}&v<|dQRAGyDowi%q&)O3zGjhzZ$n=hC^wFLz_`Z*q)|ztU zjTm_(^9`HWSOdir{)%kp2X`L5e04h;Y2CBc_v?O0E{ScIFG-t-XztS07VGwLG-f1K?O+T4%|U z&GEAyTo1v5zii>rDmCTaqCp9FBP7q{^?U1P^NQ7L=@Hiul6jWDg1g(Y6j2$U^km&O zXM7TO*=F-*!si{e0u{wH&!1vtZ~kMC-`cnXm6;Y>vt^kL0YVLno@}SZU&xrCqC|pw z+@uUGwYTL(+n?4ZJ9A#_2@%oZoOry(1XrqtMNB+ic7$upBxua61X`s4c&z4Y@^}78 z{$`_Pi_B-^{l(9VUyf$KoaerLdE$9a6la1^e`Dq}|Jc(rub$~2_;R_^r+SpTb@tNj zJkN&s#($>8X#Ga9+6Oa+jm}-sh~%6i%^&U&>CnRk*P_}^ilLVAhiTQ$lv$mCOM1!S zUZ)!z*)|4>%%YW##BXk#>Qy)tsK8X~c2ZPiewkZPQPDae!P~^%;7<5#u(O~(>MvhL zdnoyi;T?f(KeRbkq-o(w?XLZ_?SIIh3F9O}8X!KbCC73n#SJE_yPo&Ok9AJ3QZ+xM zIrCXXHYM&9Z#|Y)Ohw&(*2*x^?N8n?Xz>vRyog<4N!cTyf<>_1_7uuR^A(FH_r$>I zxL^cpDo>DfZ^&-7P_?8#u3IFaMOYdwQp40#3MX=%hNA0aRSHG^+ou-xi7WiI0-zt{ YVI1vz!!;KfL&A4gXAh^kO_U@52V3Mv=l}o! From 9c0342624e052c617eed1f6f8731e30bb030a0cd Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Mon, 4 Dec 2023 13:01:58 -0600 Subject: [PATCH 28/41] emit also node length --- src/subcommand/paths_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/subcommand/paths_main.cpp b/src/subcommand/paths_main.cpp index c33904ee8..f531ea4cb 100644 --- a/src/subcommand/paths_main.cpp +++ b/src/subcommand/paths_main.cpp @@ -416,7 +416,7 @@ int main_paths(int argc, char** argv) { } // Emit non-reference nodes - std::cout << "#node.id\tpaths" << std::endl; + std::cout << "#node.id\tnode.len\tpaths" << std::endl; for (auto x : non_reference_nodes) { const handle_t handle = graph.get_handle(x + shift); @@ -433,7 +433,7 @@ int main_paths(int argc, char** argv) { result += graph.get_path_name(path); } - std::cout << graph.get_id(handle) << "\t" << result << std::endl; + std::cout << graph.get_id(handle) << "\t" << graph.get_length(handle) << "\t" << result << std::endl; } } else { // Emit non-reference ranges From 245b6c66fce99f43b8a818dc106665824690761b Mon Sep 17 00:00:00 2001 From: Erik Garrison Date: Mon, 18 Dec 2023 14:43:08 -0600 Subject: [PATCH 29/41] fix nix build pkgconfig issue --- default.nix | 2 +- odgi.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/default.nix b/default.nix index 91b82fa8a..756bd8a73 100644 --- a/default.nix +++ b/default.nix @@ -1,5 +1,5 @@ { pkgs ? import {} }: pkgs.callPackage ./odgi.nix { - inherit (pkgs) stdenv fetchFromGitHub cmake jemalloc pkgconfig python3 gcc zlib htslib gsl; + inherit (pkgs) stdenv fetchFromGitHub cmake jemalloc pkg-config python3 gcc zlib htslib gsl; } diff --git a/odgi.nix b/odgi.nix index f3dc49a20..e13b16e59 100644 --- a/odgi.nix +++ b/odgi.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, fetchFromGitHub, cmake, jemalloc, python3, pkgconfig, gcc, git, zlib, htslib, gsl }: +{ lib, stdenv, fetchFromGitHub, cmake, jemalloc, python3, pkg-config, gcc, git, zlib, htslib, gsl }: stdenv.mkDerivation rec { pname = "odgi"; @@ -12,7 +12,7 @@ stdenv.mkDerivation rec { fetchSubmodules = true; }; - nativeBuildInputs = [ cmake pkgconfig ]; + nativeBuildInputs = [ cmake pkg-config ]; buildInputs = [ jemalloc From 02958e23a178dec7666916e76ea52048ab1088c8 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Mon, 8 Jan 2024 13:22:38 +0100 Subject: [PATCH 30/41] deactivate 1D layout metrics in MultiQC mode --- src/subcommand/stats_main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/subcommand/stats_main.cpp b/src/subcommand/stats_main.cpp index 6ee48b7cb..15d06110d 100644 --- a/src/subcommand/stats_main.cpp +++ b/src/subcommand/stats_main.cpp @@ -167,7 +167,7 @@ int main_stats(int argc, char** argv) { const uint64_t shift = number_bool_packing::unpack_number(graph.get_handle(graph.min_node_id())); - if (args::get(mean_links_length) || args::get(sum_of_path_node_distances) || _multiqc) { + if (args::get(mean_links_length) || args::get(sum_of_path_node_distances)) { if (number_bool_packing::unpack_number(graph.get_handle(graph.max_node_id())) - shift >= graph.get_node_count()){ std::cerr << "[odgi::stats] error: the node IDs are not compacted. Please run 'odgi sort' using -O, --optimize to optimize the graph." << std::endl; exit(1); @@ -371,7 +371,7 @@ int main_stats(int argc, char** argv) { // TODO clear all sets? } - if (args::get(mean_links_length) || args::get(sum_of_path_node_distances) || _multiqc) { + if (args::get(mean_links_length) || args::get(sum_of_path_node_distances)) { // This vector is needed for computing the metrics in 1D and for detecting gap-links std::vector position_map(graph.get_node_count() + 1); @@ -409,7 +409,7 @@ int main_stats(int argc, char** argv) { position_map[position_map.size() - 1] = len; } - if (args::get(mean_links_length) || _multiqc){ + if (args::get(mean_links_length)){ bool _dont_penalize_gap_links = args::get(dont_penalize_gap_links); uint64_t sum_all_node_space = 0; @@ -582,7 +582,7 @@ int main_stats(int argc, char** argv) { } } - if (args::get(sum_of_path_node_distances) || _multiqc){ + if (args::get(sum_of_path_node_distances)){ bool _penalize_diff_orientation = args::get(penalize_diff_orientation); uint64_t sum_all_path_node_dist_node_space = 0; From 4cbc1b46e35b4371e1f21e3a8e958aebd9ea15df Mon Sep 17 00:00:00 2001 From: subwaystation Date: Wed, 31 Jan 2024 14:43:30 +0100 Subject: [PATCH 31/41] sort layout power up --- docs/img/DRB1-3123_sorting_layouting.png | Bin 46738 -> 72739 bytes docs/index.rst | 2 +- docs/rst/quick_start.rst | 6 +++--- docs/rst/tutorials/sort_layout.rst | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/img/DRB1-3123_sorting_layouting.png b/docs/img/DRB1-3123_sorting_layouting.png index f001bd45fc6e7bc812870addf6feb3b5127a6a22..45c2192c64a0405a43f887be654c9628552a042d 100644 GIT binary patch literal 72739 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 RI{{-zR28)ps-C|J{$GV9(!~G( literal 46738 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 diff --git a/docs/index.rst b/docs/index.rst index 4615dbbae..1e7adf14a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -79,7 +79,7 @@ Core Functionalities :target: rst/tutorials/extract_selected_loci.html .. |sorting_layouting| image:: img/DRB1-3123_sorting_layouting.png - :target: rst/tutorials/sorting_layouting.html + :target: rst/tutorials/sort_layout.html .. |navigating_and_annotating_graphs| image:: img/nav_welcome.png :target: rst/tutorials/navigating_and_annotating_graphs.html diff --git a/docs/rst/quick_start.rst b/docs/rst/quick_start.rst index c61a171c3..b8da269e7 100644 --- a/docs/rst/quick_start.rst +++ b/docs/rst/quick_start.rst @@ -18,12 +18,12 @@ version 1 (`GFAv1 `_) Build graph from GFA ---------------------------- -Assuming that your current working directory is the root of the ``odgi`` project, to construct an ``odgi`` file from a -``GFA`` file, execute: +To construct an ``odgi`` file from a ``GFA`` file, execute: .. code-block:: bash - odgi build -g test/DRB1-3123.gfa -o DRB1-3123.og + wget https://raw.githubusercontent.com/pangenome/odgi/master/test/DRB1-3123.gfa + odgi build -g DRB1-3123.gfa -o DRB1-3123.og The command creates a file called ``DRB1-3123.og``, which contains the input graph in ``odgi`` format. diff --git a/docs/rst/tutorials/sort_layout.rst b/docs/rst/tutorials/sort_layout.rst index 8cbf5dd61..2ce086d1f 100644 --- a/docs/rst/tutorials/sort_layout.rst +++ b/docs/rst/tutorials/sort_layout.rst @@ -39,12 +39,12 @@ to take a look at the calculated layout using static and interactive tools. Build the unsorted DRB1-3123 graph ---------------------------------- -Assuming that your current working directory is the root of the ``odgi`` project, to construct an ``odgi`` graph from the -``DRB1-3123`` dataset in ``GFA`` format, execute: +To construct an ``odgi`` graph from the ``DRB1-3123`` dataset in ``GFA`` format, execute: .. code-block:: bash - odgi build -g test/DRB1-3123_unsorted.gfa -o DRB1-3123_unsorted.og + wget https://raw.githubusercontent.com/pangenome/odgi/master/test/DRB1-3123_unsorted.gfa + odgi build -g DRB1-3123_unsorted.gfa -o DRB1-3123_unsorted.og The command creates a file called ``DRB1-3123_unsorted.og``, which contains the input graph in ``odgi`` format. This graph contains 12 ALT sequences of the `HLA-DRB1 gene `_ from the GRCh38 reference genome. From d32b34d8f10234f5b8fe78c20a3f34a0e3f1ef17 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Wed, 31 Jan 2024 14:44:45 +0100 Subject: [PATCH 32/41] fix line indents --- docs/rst/quick_start.rst | 2 +- docs/rst/tutorials/sort_layout.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rst/quick_start.rst b/docs/rst/quick_start.rst index b8da269e7..c399191b9 100644 --- a/docs/rst/quick_start.rst +++ b/docs/rst/quick_start.rst @@ -22,7 +22,7 @@ To construct an ``odgi`` file from a ``GFA`` file, execute: .. code-block:: bash - wget https://raw.githubusercontent.com/pangenome/odgi/master/test/DRB1-3123.gfa + wget https://raw.githubusercontent.com/pangenome/odgi/master/test/DRB1-3123.gfa odgi build -g DRB1-3123.gfa -o DRB1-3123.og The command creates a file called ``DRB1-3123.og``, which contains the input graph in ``odgi`` format. diff --git a/docs/rst/tutorials/sort_layout.rst b/docs/rst/tutorials/sort_layout.rst index 2ce086d1f..fde2db25e 100644 --- a/docs/rst/tutorials/sort_layout.rst +++ b/docs/rst/tutorials/sort_layout.rst @@ -43,7 +43,7 @@ To construct an ``odgi`` graph from the ``DRB1-3123`` dataset in ``GFA`` format, .. code-block:: bash - wget https://raw.githubusercontent.com/pangenome/odgi/master/test/DRB1-3123_unsorted.gfa + wget https://raw.githubusercontent.com/pangenome/odgi/master/test/DRB1-3123_unsorted.gfa odgi build -g DRB1-3123_unsorted.gfa -o DRB1-3123_unsorted.og The command creates a file called ``DRB1-3123_unsorted.og``, which contains the input graph in ``odgi`` format. This graph contains From 970a1f78b6d469e2dc815935ebc393b13f5ecff5 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 1 Feb 2024 11:32:57 +0100 Subject: [PATCH 33/41] update MultiQC tutorial --- docs/conf.py | 6 +++--- docs/rst/multiqc.rst | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 9950659bc..ae510f9e2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,13 +20,13 @@ # -- Project information ----------------------------------------------------- project = u'odgi' -copyright = '2020-2023, *Guarracino A., *Heumos S., Nahnsen S., Prins P., Garrison E. Revision v0.8.2-1fa78aa' +copyright = '2020-2022, *Guarracino A., *Heumos S., Nahnsen S., Prins P., Garrison E. Revision v0.8.4-d7ef5c6b' author = u'*Andrea Guarracino, *Simon Heumos, Sven Nahnsen, Pjotr Prins, Erik Garrison' # The short X.Y version -version = 'v0.8.2' +version = 'v0.8.4' # The full version, including alpha/beta/rc tags -release = '1fa78aa' +release = 'd7ef5c6b' # -- General configuration --------------------------------------------------- diff --git a/docs/rst/multiqc.rst b/docs/rst/multiqc.rst index 4ac7e04e4..ddf3972cc 100644 --- a/docs/rst/multiqc.rst +++ b/docs/rst/multiqc.rst @@ -4,7 +4,7 @@ MultiQC Module ============== -Since v1.11 `MultiQC `_ has an `ODGI module `_. This module can only +Since v1.19 `MultiQC `_ has an `ODGI module `_. This module can only work with output from :ref:`odgi stats`! In the following, it is shown how to use ODGI in order to get a nice MultiQC report. --------------- @@ -38,7 +38,7 @@ To see the full statistics in YAML format of the graph, execute: .. code-block:: bash - odgi stats -i DRB1-3123.gfa.og -m + odgi stats -i DRB1-3123.gfa.og -m -sgdl This prints the following YAML to stdout: @@ -89,7 +89,7 @@ Let's save the statistics this time: .. code-block:: bash - odgi stats -i DRB1-3123.gfa.og -m > DRB1-3123.gfa.og.stats.yaml + odgi stats -i DRB1-3123.gfa.og -m -sgdl > DRB1-3123.gfa.og.stats.yaml .. note:: @@ -167,7 +167,7 @@ Assuming, we have several graphs, of which we want to compare the statistics fro .. code-bock:: bash odgi build -g LPA.gfa -o LPA.gfa.og - odgi stats -i LPA.gfa.og -y > LPA.gfa.og.stats.yaml + odgi stats -i LPA.gfa.og -m -sgdl > LPA.gfa.og.stats.yaml odgi viz -i LPA.gfa.og -o LPA.gfa.og.viz_mqc.png odgi layout -i LPA.gfa.og -o LPA.gfa.og.lay odgi draw -i LPA.gfa.og -c LPA.gfa.og.lay -p LPA.gfa.og.lay.draw_mqc.png -w 10 -C From 842d629dfaf5e52802ed0130def6742d5e52b454 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 1 Feb 2024 11:33:13 +0100 Subject: [PATCH 34/41] update sort layout tutorial --- docs/rst/tutorials/sort_layout.rst | 39 +++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/rst/tutorials/sort_layout.rst b/docs/rst/tutorials/sort_layout.rst index fde2db25e..2e93823c3 100644 --- a/docs/rst/tutorials/sort_layout.rst +++ b/docs/rst/tutorials/sort_layout.rst @@ -1,4 +1,4 @@ -.. _sorting-layouting: +.. _sort-layout: ############### Sort and Layout @@ -16,6 +16,8 @@ a 1D and 2D layout to simplify these complex regions. This tutorial shows how to sort and visualize a graph in 1D. It explains how to generate a 2D layout of a graph, and how to take a look at the calculated layout using static and interactive tools. +For more details about the applied algorithm, please take a look at https://www.biorxiv.org/content/10.1101/2023.09.22.558964v2. + .. Pangenome graphs embed linear pangenomic sequences as paths in .. the graph, but to our knowledge, no algorithm takes into account this biological information in the sorting. Moreover, .. existing 2D layout methods struggle to deal with large graphs. ``odgi`` implements a new layout algorithm to simplify a pangenome @@ -129,6 +131,22 @@ nodes. .. note:: The PG-SGD is not deterministic, because of its `Hogwild! `_ approach. + For more details about the applied algorithm, please take a look at https://www.biorxiv.org/content/10.1101/2023.09.22.558964v2. + +.. note:: + The 1D PG-SGD implementation comes with a huge amount of tunable parameters. Based on our experience applying it to hundreds of graphs, the current + defaults usually work well for most graphs. However, if you feel the sorting did not work well enough, there are 2 key parameters one can tune: + + | **-G, --path-sgd-min-term-updates-paths**\ =\ *N*: The minimum number of terms to be + updated before a new path-guided + linear 1D SGD iteration with adjusted + learning rate eta starts, expressed as + a multiple of total path steps (default: 1.0). + | **-x, --path-sgd-iter-max**\ =\ *N*: The maximum number of iterations for path-guided linear 1D SGD model (default: 100). + + Increasing both can lead to a better sorted graph. For example, one can start optimizing with setting **-x, --path-sgd-iter-max**\ =\ *200*. + For more parameter details please take + a look at :ref:`odgi sort`. .. To reproduce the visualization below, the sorted graph can be found under ``test/DRB1-3123_sorted.og``. @@ -267,6 +285,8 @@ We can clearly observe, that the path positions of the two reference now define 2D layout ========= +The 2D PG-SGD layout algorithm is described in https://www.biorxiv.org/content/10.1101/2023.09.22.558964v2. + ----------------------------------------- 2D layout of the unsorted DRB1-3123 graph ----------------------------------------- @@ -277,6 +297,23 @@ We want to have a 2D layout of our DRB1-3123 graph: odgi layout -i DRB1-3123_unsorted.og -o DRB1-3123_unsorted.og.lay -P --threads 2 +.. note:: + The 2D PG-SGD implementation comes with a huge amount of tunable parameters. Based on our experience applying it to hundreds of graphs, the current + defaults usually work well for most graphs. However, if you feel the resulting 2D layout is not of a good enough quality, there are 2 key parameters one can tune: + + | **-G, --path-sgd-min-term-updates-paths**\ =\ *N*: Minimum number of terms N to be + updated before a new path-guided 2D + SGD iteration with adjusted learning + rate eta starts, expressed as a + multiple of total path length + (default: 10). + | **-x, --path-sgd-iter-max**\ =\ *N*: The maximum number of iterations N for + the path-guided 2D SGD model (default: + 30). + + Increasing both can lead to a better graph layout. For example, one can start optimizing with setting **-x, --path-sgd-iter-max**\ =\ *100*. + For more parameter details please take a look at :ref:`odgi layout`. + -------------------------------------------- Drawing the 2D layout of the DRB1-3123 graph -------------------------------------------- From 3eb4224a9e09c763d08ab881c288ba7fd3ac201f Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 1 Feb 2024 11:33:26 +0100 Subject: [PATCH 35/41] update sort layout tutorial --- docs/rst/commands/odgi_sort.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/rst/commands/odgi_sort.rst b/docs/rst/commands/odgi_sort.rst index 274664a90..5f6c8a17c 100644 --- a/docs/rst/commands/odgi_sort.rst +++ b/docs/rst/commands/odgi_sort.rst @@ -49,9 +49,8 @@ order: force-directed graph drawing algorithm minimizes the graph’s energy function or stress level. It applies stochastic gradient descent (SGD) to move a single pair of nodes at a time. The path index is - used to pick the terms to move stochastically. If ran with 1 thread - only, the resulting order of the graph is deterministic. The seed is - adjustable. + used to pick the terms to move stochastically. For more details about + the algorithm, please take a look at https://www.biorxiv.org/content/10.1101/2023.09.22.558964v2. Sorting the paths in a graph my refine the sorting process. For the users’ convenience, it is possible to specify a whole pipeline of sorts From eb96c6b32447f645b98be5fecbba7b94800ab9fa Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 1 Feb 2024 11:34:27 +0100 Subject: [PATCH 36/41] correct copyright year --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index ae510f9e2..2bd5b6652 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,7 +20,7 @@ # -- Project information ----------------------------------------------------- project = u'odgi' -copyright = '2020-2022, *Guarracino A., *Heumos S., Nahnsen S., Prins P., Garrison E. Revision v0.8.4-d7ef5c6b' +copyright = '2020-2024, *Guarracino A., *Heumos S., Nahnsen S., Prins P., Garrison E. Revision v0.8.4-d7ef5c6b' author = u'*Andrea Guarracino, *Simon Heumos, Sven Nahnsen, Pjotr Prins, Erik Garrison' # The short X.Y version From f4eeb5b5300017931b85e2c0210fe72aaf214f1f Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 1 Feb 2024 11:35:00 +0100 Subject: [PATCH 37/41] typo --- docs/rst/multiqc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rst/multiqc.rst b/docs/rst/multiqc.rst index ddf3972cc..ed17cdc1a 100644 --- a/docs/rst/multiqc.rst +++ b/docs/rst/multiqc.rst @@ -4,7 +4,7 @@ MultiQC Module ============== -Since v1.19 `MultiQC `_ has an `ODGI module `_. This module can only +Since v1.11 `MultiQC `_ has an `ODGI module `_. This module can only work with output from :ref:`odgi stats`! In the following, it is shown how to use ODGI in order to get a nice MultiQC report. --------------- From 6bf8674d01857cf58aca2820dd0a12c498d554b5 Mon Sep 17 00:00:00 2001 From: subwaystation Date: Thu, 1 Feb 2024 13:55:36 +0100 Subject: [PATCH 38/41] Playing around with the 1D PG-SGD parameters --- docs/conf.py | 4 +- docs/img/DRB1-3123_sorted.U1000.png | Bin 0 -> 4934 bytes docs/img/DRB1-3123_sorted.j10000.png | Bin 0 -> 10682 bytes docs/img/DRB1-3123_sorted.x2.png | Bin 0 -> 13928 bytes docs/rst/tutorials/exploratory_analysis.rst | 2 +- docs/rst/tutorials/sort_layout.rst | 67 ++++++++++++++++++++ 6 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 docs/img/DRB1-3123_sorted.U1000.png create mode 100644 docs/img/DRB1-3123_sorted.j10000.png create mode 100644 docs/img/DRB1-3123_sorted.x2.png diff --git a/docs/conf.py b/docs/conf.py index 2bd5b6652..11f169916 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,13 +20,13 @@ # -- Project information ----------------------------------------------------- project = u'odgi' -copyright = '2020-2024, *Guarracino A., *Heumos S., Nahnsen S., Prins P., Garrison E. Revision v0.8.4-d7ef5c6b' +copyright = '2020-2024, *Guarracino A., *Heumos S., Nahnsen S., Prins P., Garrison E. Revision v0.8.4-a19163ea' author = u'*Andrea Guarracino, *Simon Heumos, Sven Nahnsen, Pjotr Prins, Erik Garrison' # The short X.Y version version = 'v0.8.4' # The full version, including alpha/beta/rc tags -release = 'd7ef5c6b' +release = 'a19163ea' # -- General configuration --------------------------------------------------- diff --git a/docs/img/DRB1-3123_sorted.U1000.png b/docs/img/DRB1-3123_sorted.U1000.png new file mode 100644 index 0000000000000000000000000000000000000000..73efc36454ff845184a1b2b1669c643fca71e3d5 GIT binary patch literal 4934 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 aep|$6lj5s=8_d7L039v;i^Ugg!v72EhGf(L literal 0 HcmV?d00001 diff --git a/docs/img/DRB1-3123_sorted.j10000.png b/docs/img/DRB1-3123_sorted.j10000.png new file mode 100644 index 0000000000000000000000000000000000000000..d3b2e39e81b22d8ee3572047a8c37df28366f108 GIT binary patch literal 10682 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 Xq;dDqxWL>jhNY`%pi!shl<@xn9>S6i literal 0 HcmV?d00001 diff --git a/docs/rst/tutorials/exploratory_analysis.rst b/docs/rst/tutorials/exploratory_analysis.rst index 7db08d80b..35cd38b1d 100644 --- a/docs/rst/tutorials/exploratory_analysis.rst +++ b/docs/rst/tutorials/exploratory_analysis.rst @@ -76,7 +76,7 @@ Color with respect to the node position This is a linearized visualization, but the pangenome graphs are not linear when the embedded genomes present structural variation. However, a graph can be optimized for being better visualized in 1-Dimension by sorting its nodes properly -(see the :ref:`sorting-layouting` tutorial for more information). +(see the :ref:`sort-layout` tutorial for more information). To color the bars with respect to the node position in each path, execute: diff --git a/docs/rst/tutorials/sort_layout.rst b/docs/rst/tutorials/sort_layout.rst index 2e93823c3..517a3fd4f 100644 --- a/docs/rst/tutorials/sort_layout.rst +++ b/docs/rst/tutorials/sort_layout.rst @@ -187,6 +187,73 @@ This prints to stdout: Compared to before, these metrics show that the goodness of the sorting of the graph improved significantly. +-------------------------------------------- +Playing around with the 1D PG-SGD parameters +-------------------------------------------- + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +What happens if the maximum number of iterations is very low? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + odgi sort -i DRB1-3123_unsorted.og --threads 2 -P -Y -x 2 -o DRB1-3123_sorted.x2.og + odgi viz -i DRB1-3123_sorted.x2.og -o DRB1-3123_sorted.x2.png + +.. image:: /img/DRB1-3123_sorted.x2.png + +The graph appears very complex and not quite human readable. That's because in total there were two times the number +of total path steps node position updates instead of one hundred times the number of total path steps, which is the current default. +For very complex graphs, one may have to increase this number even further. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +What happens if the minimum number of term updates is very high? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + odgi sort -i DRB1-3123_unsorted.og --threads 2 -P -Y -U 1000 -o DRB1-3123_sorted.U1000.og + odgi viz -i DRB1-3123_sorted.U1000.og -o DRB1-3123_sorted.U1000.png + +.. image:: /img/DRB1-3123_sorted.U1000.png + +The graph lost it's complexity and is now linear. Compared to the 1D visualization using the default parameters, it is hard +to spot any differences. So let's take a look at the metrics: + +.. code-block:: bash + + odgi stats -i DRB1-3123_sorted.U1000.og -s -d -l -g + +This prints to stdout: + +.. code-block:: bash + + #mean_links_length + path in_node_space in_nucleotide_space num_links_considered num_gap_links_not_penalized + all_paths 1.00361 8.30677 21870 15195 + #sum_of_path_node_distances + path in_node_space in_nucleotide_space nodes nucleotides num_penalties num_penalties_different_orientation + all_paths 3.23238 3.73489 21882 163416 3750 1 + +We actually were able to improve the metrics compared to using default parameters. However, the runtime increased from under 1 second to ~30 seconds. +So one needs to be careful with such a parameter. Compared to the gains in linearity, such an additional time usage would be a huge +waste with very large graphs. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +What happens if the threshold of the maximum distance of two nodes is very high? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + odgi sort -i DRB1-3123_unsorted.og --threads 2 -P -Y -j 10000 -o DRB1-3123_sorted.j10000.og + odgi viz -i DRB1-3123_sorted.j10000.og -o DRB1-3123_sorted.j10000.png + +.. image:: /img/DRB1-3123_sorted.j10000.png + +The graph appears very complex and not quite human readable. That's because the iterations are terminated as soon as the +expected distance of two nodes, the nucleotide distance given by two randomly chosen path steps, is as close as 10000. +Naturally, this happens very soon. + ========================================================= 1D reference-guided grooming and reference-guided sorting ========================================================= From 6e7efd0d1dd045d915584378b664eab063080ac3 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Fri, 2 Feb 2024 14:43:31 -0600 Subject: [PATCH 39/41] I-fell-lucky commit --- .readthedocs.yaml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..dd2aa46c8 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,35 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + # You can also specify other tool versions: + # nodejs: "20" + # rust: "1.70" + # golang: "1.20" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs + # builder: "dirhtml" + # Fail on all warnings to avoid broken references + # fail_on_warning: true + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt From 7bbc2af6bb6603cd63a8b2c1e7ec3445e4716fcd Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Fri, 2 Feb 2024 14:47:33 -0600 Subject: [PATCH 40/41] python requirements --- .readthedocs.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index dd2aa46c8..31dbf0d70 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -30,6 +30,6 @@ sphinx: # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt +python: + install: + - requirements: docs/requirements.txt From 5a6e8341edeed3e2981364069798349320f61d05 Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Fri, 2 Feb 2024 14:50:51 -0600 Subject: [PATCH 41/41] sphinx-rtd-theme --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 0da073719..47a606942 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ breathe m2r2 asciidoc +sphinx-rtd-theme