@gmod/gbz-base 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -26
- package/bin/query.js +0 -0
- package/dist/cli.js +76 -28
- package/dist/cli.js.map +1 -1
- package/dist/db.d.ts +26 -9
- package/dist/db.js +158 -24
- package/dist/db.js.map +1 -1
- package/dist/gbwt/record.d.ts +4 -0
- package/dist/gbwt/record.js +22 -0
- package/dist/gbwt/record.js.map +1 -1
- package/dist/graphName.d.ts +9 -0
- package/dist/graphName.js +83 -0
- package/dist/graphName.js.map +1 -0
- package/dist/index.d.ts +8 -5
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/pathName.d.ts +17 -0
- package/dist/pathName.js +33 -0
- package/dist/pathName.js.map +1 -0
- package/dist/query.d.ts +9 -9
- package/dist/query.js +23 -17
- package/dist/query.js.map +1 -1
- package/dist/sqlite/btree.d.ts +2 -0
- package/dist/sqlite/btree.js +55 -20
- package/dist/sqlite/btree.js.map +1 -1
- package/dist/sqlite/pager.d.ts +5 -0
- package/dist/sqlite/pager.js +65 -8
- package/dist/sqlite/pager.js.map +1 -1
- package/dist/subgraph.d.ts +34 -11
- package/dist/subgraph.js +346 -87
- package/dist/subgraph.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +85 -24
- package/src/db.ts +225 -33
- package/src/gbwt/record.ts +23 -0
- package/src/graphName.ts +94 -0
- package/src/index.ts +15 -10
- package/src/pathName.ts +54 -0
- package/src/query.ts +41 -29
- package/src/sqlite/btree.ts +68 -19
- package/src/sqlite/pager.ts +78 -8
- package/src/subgraph.ts +430 -114
- package/tools/haplotype-index/src/main.rs +205 -163
|
@@ -7,22 +7,39 @@ use simple_sds::serialize;
|
|
|
7
7
|
|
|
8
8
|
use std::env;
|
|
9
9
|
use std::process;
|
|
10
|
+
use std::thread;
|
|
11
|
+
use std::time::Instant;
|
|
10
12
|
|
|
11
|
-
const USAGE: &str = "Usage: gbz-haplotype-index [
|
|
12
|
-
gbz-haplotype-index [
|
|
13
|
+
const USAGE: &str = "Usage: gbz-haplotype-index [options] graph.gbz graph.gbz.db
|
|
14
|
+
gbz-haplotype-index [options] --output index.db graph.gbz [graph.gbz.db]
|
|
15
|
+
gbz-haplotype-index [options] --from-db graph.gbz.db
|
|
13
16
|
|
|
14
17
|
Walks every path in both orientations and writes a sample every --interval bp
|
|
15
|
-
(default 4096) into table HaplotypeSamples
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
the
|
|
18
|
+
(default 4096) into table HaplotypeSamples, plus the path lengths into
|
|
19
|
+
HaplotypeLengths. The path start and end are always sampled.
|
|
20
|
+
|
|
21
|
+
By default the tables are written into the database itself, replacing any
|
|
22
|
+
existing ones. With --output FILE they are written into FILE as a standalone
|
|
23
|
+
companion database that the reader opens beside the graph database; the
|
|
24
|
+
companion records the graph's path count so a mismatch is caught at open.
|
|
25
|
+
|
|
26
|
+
With --from-db the walk reads node records from the database itself, so the
|
|
27
|
+
GBZ is not needed. Walking a GBZ uses --threads (default: all cores).
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--interval BP bp between samples along a path (default 4096)
|
|
31
|
+
--forward-only sample only the forward orientation of each path
|
|
32
|
+
--output FILE write a companion database instead of augmenting graph.gbz.db
|
|
33
|
+
--threads N walker threads for the GBZ route
|
|
19
34
|
";
|
|
20
35
|
|
|
21
36
|
struct Args {
|
|
22
37
|
gbz: Option<String>,
|
|
23
|
-
db: String
|
|
38
|
+
db: Option<String>,
|
|
39
|
+
output: Option<String>,
|
|
24
40
|
interval: usize,
|
|
25
41
|
forward_only: bool,
|
|
42
|
+
threads: usize,
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
fn parse_args() -> Args {
|
|
@@ -30,6 +47,8 @@ fn parse_args() -> Args {
|
|
|
30
47
|
let mut interval = 4096;
|
|
31
48
|
let mut forward_only = false;
|
|
32
49
|
let mut from_db = false;
|
|
50
|
+
let mut output = None;
|
|
51
|
+
let mut threads = thread::available_parallelism().map(|n| n.get()).unwrap_or(1);
|
|
33
52
|
let mut iter = env::args().skip(1);
|
|
34
53
|
while let Some(arg) = iter.next() {
|
|
35
54
|
match arg.as_str() {
|
|
@@ -40,6 +59,14 @@ fn parse_args() -> Args {
|
|
|
40
59
|
process::exit(1);
|
|
41
60
|
});
|
|
42
61
|
}
|
|
62
|
+
"--threads" => {
|
|
63
|
+
let value = iter.next().unwrap_or_default();
|
|
64
|
+
threads = value.parse().unwrap_or_else(|_| {
|
|
65
|
+
eprintln!("Invalid --threads: {}", value);
|
|
66
|
+
process::exit(1);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
"--output" => output = Some(iter.next().unwrap_or_default()),
|
|
43
70
|
"--forward-only" => forward_only = true,
|
|
44
71
|
"--from-db" => from_db = true,
|
|
45
72
|
"-h" | "--help" => {
|
|
@@ -49,46 +76,52 @@ fn parse_args() -> Args {
|
|
|
49
76
|
_ => positional.push(arg),
|
|
50
77
|
}
|
|
51
78
|
}
|
|
52
|
-
let
|
|
53
|
-
|
|
79
|
+
let valid = if from_db {
|
|
80
|
+
positional.len() == 1
|
|
81
|
+
} else if output.is_some() {
|
|
82
|
+
positional.len() == 1 || positional.len() == 2
|
|
83
|
+
} else {
|
|
84
|
+
positional.len() == 2
|
|
85
|
+
};
|
|
86
|
+
if !valid || interval == 0 || threads == 0 {
|
|
54
87
|
eprint!("{}", USAGE);
|
|
55
88
|
process::exit(1);
|
|
56
89
|
}
|
|
57
|
-
let db =
|
|
58
|
-
|
|
59
|
-
|
|
90
|
+
let (gbz, db) = if from_db {
|
|
91
|
+
(None, positional.pop())
|
|
92
|
+
} else {
|
|
93
|
+
let gbz = positional.remove(0);
|
|
94
|
+
(Some(gbz), positional.pop())
|
|
95
|
+
};
|
|
96
|
+
Args { gbz, db, output, interval, forward_only, threads }
|
|
60
97
|
}
|
|
61
98
|
|
|
99
|
+
#[derive(Clone, Copy)]
|
|
62
100
|
struct Sample {
|
|
63
|
-
node_handle:
|
|
64
|
-
node_offset:
|
|
65
|
-
path_handle:
|
|
66
|
-
orientation:
|
|
67
|
-
path_offset:
|
|
101
|
+
node_handle: u32,
|
|
102
|
+
node_offset: u32,
|
|
103
|
+
path_handle: u32,
|
|
104
|
+
orientation: u8,
|
|
105
|
+
path_offset: u32,
|
|
68
106
|
}
|
|
69
107
|
|
|
70
108
|
trait PathSource {
|
|
71
|
-
fn
|
|
72
|
-
fn
|
|
73
|
-
fn
|
|
74
|
-
fn node_len(&mut self, handle: usize) -> usize;
|
|
109
|
+
fn start(&self, path_handle: usize, orientation: Orientation) -> Option<Pos>;
|
|
110
|
+
fn step(&self, pos: Pos) -> (usize, Option<Pos>);
|
|
111
|
+
fn node_len(&self, handle: usize) -> usize;
|
|
75
112
|
}
|
|
76
113
|
|
|
77
|
-
struct GbzSource {
|
|
78
|
-
graph: GBZ,
|
|
114
|
+
struct GbzSource<'a> {
|
|
115
|
+
graph: &'a GBZ,
|
|
79
116
|
}
|
|
80
117
|
|
|
81
|
-
impl PathSource for GbzSource {
|
|
82
|
-
fn
|
|
83
|
-
self.graph.metadata().map(|m| m.paths()).unwrap_or(0)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
fn start(&mut self, path_handle: usize, orientation: Orientation) -> Option<Pos> {
|
|
118
|
+
impl PathSource for GbzSource<'_> {
|
|
119
|
+
fn start(&self, path_handle: usize, orientation: Orientation) -> Option<Pos> {
|
|
87
120
|
let index: &GBWT = self.graph.as_ref();
|
|
88
121
|
index.start(support::encode_path(path_handle, orientation))
|
|
89
122
|
}
|
|
90
123
|
|
|
91
|
-
fn step(&
|
|
124
|
+
fn step(&self, pos: Pos) -> (usize, Option<Pos>) {
|
|
92
125
|
let node_len = self.graph.sequence_len(support::node_id(pos.node)).unwrap();
|
|
93
126
|
let index: &GBWT = self.graph.as_ref();
|
|
94
127
|
let bwt: &BWT = index.as_ref();
|
|
@@ -96,42 +129,37 @@ impl PathSource for GbzSource {
|
|
|
96
129
|
(node_len, record.lf(pos.offset))
|
|
97
130
|
}
|
|
98
131
|
|
|
99
|
-
fn node_len(&
|
|
132
|
+
fn node_len(&self, handle: usize) -> usize {
|
|
100
133
|
self.graph.sequence_len(support::node_id(handle)).unwrap()
|
|
101
134
|
}
|
|
102
135
|
}
|
|
103
136
|
|
|
104
137
|
struct DbSource<'a> {
|
|
105
|
-
interface: GraphInterface<'a
|
|
106
|
-
paths: usize,
|
|
138
|
+
interface: std::cell::RefCell<GraphInterface<'a>>,
|
|
107
139
|
}
|
|
108
140
|
|
|
109
|
-
impl
|
|
110
|
-
fn
|
|
111
|
-
self.
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
fn start(&mut self, path_handle: usize, orientation: Orientation) -> Option<Pos> {
|
|
115
|
-
let path = self.interface.get_path(path_handle).unwrap()?;
|
|
141
|
+
impl PathSource for DbSource<'_> {
|
|
142
|
+
fn start(&self, path_handle: usize, orientation: Orientation) -> Option<Pos> {
|
|
143
|
+
let path = self.interface.borrow_mut().get_path(path_handle).unwrap()?;
|
|
116
144
|
Some(if orientation == Orientation::Forward { path.fw_start } else { path.rev_start })
|
|
117
145
|
}
|
|
118
146
|
|
|
119
|
-
fn step(&
|
|
120
|
-
let record = self.interface.get_record(pos.node).unwrap().unwrap();
|
|
147
|
+
fn step(&self, pos: Pos) -> (usize, Option<Pos>) {
|
|
148
|
+
let record = self.interface.borrow_mut().get_record(pos.node).unwrap().unwrap();
|
|
121
149
|
(record.sequence_len(), record.to_gbwt_record().lf(pos.offset))
|
|
122
150
|
}
|
|
123
151
|
|
|
124
|
-
fn node_len(&
|
|
125
|
-
self.interface.get_record(handle).unwrap().unwrap().sequence_len()
|
|
152
|
+
fn node_len(&self, handle: usize) -> usize {
|
|
153
|
+
self.interface.borrow_mut().get_record(handle).unwrap().unwrap().sequence_len()
|
|
126
154
|
}
|
|
127
155
|
}
|
|
128
156
|
|
|
129
|
-
fn walk(source: &
|
|
130
|
-
let mut samples = Vec::new();
|
|
157
|
+
fn walk(source: &dyn PathSource, path_handle: usize, orientation: Orientation, interval: usize, samples: &mut Vec<Sample>) -> usize {
|
|
131
158
|
let mut pos = source.start(path_handle, orientation);
|
|
132
159
|
let mut offset = 0;
|
|
133
160
|
let mut next_sample = 0;
|
|
134
161
|
let mut last: Option<(Pos, usize)> = None;
|
|
162
|
+
let first = samples.len();
|
|
135
163
|
while let Some(current) = pos {
|
|
136
164
|
if current.node == ENDMARKER {
|
|
137
165
|
break;
|
|
@@ -139,11 +167,11 @@ fn walk(source: &mut dyn PathSource, path_handle: usize, orientation: Orientatio
|
|
|
139
167
|
let (node_len, next) = source.step(current);
|
|
140
168
|
if offset >= next_sample {
|
|
141
169
|
samples.push(Sample {
|
|
142
|
-
node_handle: current.node,
|
|
143
|
-
node_offset: current.offset,
|
|
144
|
-
path_handle,
|
|
145
|
-
orientation: orientation as
|
|
146
|
-
path_offset: offset,
|
|
170
|
+
node_handle: current.node as u32,
|
|
171
|
+
node_offset: current.offset as u32,
|
|
172
|
+
path_handle: path_handle as u32,
|
|
173
|
+
orientation: orientation as u8,
|
|
174
|
+
path_offset: offset as u32,
|
|
147
175
|
});
|
|
148
176
|
next_sample = offset + interval;
|
|
149
177
|
last = None;
|
|
@@ -155,74 +183,77 @@ fn walk(source: &mut dyn PathSource, path_handle: usize, orientation: Orientatio
|
|
|
155
183
|
}
|
|
156
184
|
if let Some((end, end_offset)) = last {
|
|
157
185
|
samples.push(Sample {
|
|
158
|
-
node_handle: end.node,
|
|
159
|
-
node_offset: end.offset,
|
|
160
|
-
path_handle,
|
|
161
|
-
orientation: orientation as
|
|
162
|
-
path_offset: end_offset,
|
|
186
|
+
node_handle: end.node as u32,
|
|
187
|
+
node_offset: end.offset as u32,
|
|
188
|
+
path_handle: path_handle as u32,
|
|
189
|
+
orientation: orientation as u8,
|
|
190
|
+
path_offset: end_offset as u32,
|
|
163
191
|
});
|
|
164
192
|
}
|
|
165
193
|
let length = offset;
|
|
166
194
|
if orientation == Orientation::Reverse {
|
|
167
|
-
for sample in samples.iter_mut() {
|
|
168
|
-
let node_len = source.node_len(sample.node_handle);
|
|
169
|
-
sample.path_offset = length - sample.path_offset - node_len;
|
|
195
|
+
for sample in samples[first..].iter_mut() {
|
|
196
|
+
let node_len = source.node_len(sample.node_handle as usize);
|
|
197
|
+
sample.path_offset = (length - sample.path_offset as usize - node_len) as u32;
|
|
170
198
|
}
|
|
171
199
|
}
|
|
172
|
-
|
|
200
|
+
length
|
|
173
201
|
}
|
|
174
202
|
|
|
175
|
-
fn
|
|
176
|
-
|
|
203
|
+
fn orientations(args: &Args) -> Vec<Orientation> {
|
|
204
|
+
if args.forward_only {
|
|
177
205
|
vec![Orientation::Forward]
|
|
178
206
|
} else {
|
|
179
207
|
vec![Orientation::Forward, Orientation::Reverse]
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
let mut
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
insert_sample
|
|
199
|
-
.execute(params![
|
|
200
|
-
sample.node_handle as i64,
|
|
201
|
-
sample.node_offset as i64,
|
|
202
|
-
sample.path_handle as i64,
|
|
203
|
-
sample.orientation as i64,
|
|
204
|
-
sample.path_offset as i64
|
|
205
|
-
])
|
|
206
|
-
.unwrap();
|
|
207
|
-
inserted += 1;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
insert_length.execute(params![path_handle as i64, length as i64]).unwrap();
|
|
211
|
-
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fn walk_paths(source: &dyn PathSource, handles: std::ops::Range<usize>, args: &Args, label: &str) -> (Vec<Sample>, Vec<(usize, usize)>) {
|
|
212
|
+
let mut samples = Vec::new();
|
|
213
|
+
let mut lengths = Vec::new();
|
|
214
|
+
let started = Instant::now();
|
|
215
|
+
let total = handles.len();
|
|
216
|
+
let mut walked_bp: usize = 0;
|
|
217
|
+
for (done, path_handle) in handles.enumerate() {
|
|
218
|
+
let mut length = 0;
|
|
219
|
+
for &orientation in orientations(args).iter() {
|
|
220
|
+
length = walk(source, path_handle, orientation, args.interval, &mut samples);
|
|
221
|
+
}
|
|
222
|
+
walked_bp += length;
|
|
223
|
+
lengths.push((path_handle, length));
|
|
224
|
+
if (done + 1) % 500 == 0 || done + 1 == total {
|
|
225
|
+
eprintln!("{}: {} / {} paths, {:.2} Gbp, {} samples, {:.0} s", label, done + 1, total, walked_bp as f64 / 1e9, samples.len(), started.elapsed().as_secs_f64());
|
|
212
226
|
}
|
|
213
|
-
transaction.commit().unwrap();
|
|
214
|
-
handle += batch;
|
|
215
|
-
eprintln!("{} / {} paths, {} samples", handle.min(paths), paths, inserted);
|
|
216
227
|
}
|
|
217
|
-
|
|
228
|
+
(samples, lengths)
|
|
218
229
|
}
|
|
219
230
|
|
|
220
|
-
fn
|
|
221
|
-
let
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
231
|
+
fn walk_gbz(graph: &GBZ, paths: usize, args: &Args) -> (Vec<Sample>, Vec<(usize, usize)>) {
|
|
232
|
+
let chunk = (paths + args.threads - 1) / args.threads;
|
|
233
|
+
let started = Instant::now();
|
|
234
|
+
let results: Vec<(Vec<Sample>, Vec<(usize, usize)>)> = thread::scope(|scope| {
|
|
235
|
+
let workers: Vec<_> = (0..args.threads)
|
|
236
|
+
.map(|t| {
|
|
237
|
+
let range = (t * chunk).min(paths)..((t + 1) * chunk).min(paths);
|
|
238
|
+
scope.spawn(move || {
|
|
239
|
+
let source = GbzSource { graph };
|
|
240
|
+
let label = format!("thread {} (paths {}..{})", t, range.start, range.end);
|
|
241
|
+
let result = walk_paths(&source, range.clone(), args, &label);
|
|
242
|
+
eprintln!("{} done in {:.0} s", label, started.elapsed().as_secs_f64());
|
|
243
|
+
result
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
.collect();
|
|
247
|
+
workers.into_iter().map(|w| w.join().unwrap()).collect()
|
|
248
|
+
});
|
|
249
|
+
let mut samples = Vec::new();
|
|
250
|
+
let mut lengths = Vec::new();
|
|
251
|
+
for (s, l) in results {
|
|
252
|
+
samples.extend(s);
|
|
253
|
+
lengths.extend(l);
|
|
254
|
+
}
|
|
255
|
+
lengths.sort_unstable();
|
|
256
|
+
(samples, lengths)
|
|
226
257
|
}
|
|
227
258
|
|
|
228
259
|
const SCHEMA: &str = "CREATE TABLE HaplotypeSamples (
|
|
@@ -238,82 +269,93 @@ CREATE TABLE HaplotypeLengths (
|
|
|
238
269
|
length INTEGER NOT NULL
|
|
239
270
|
) STRICT;";
|
|
240
271
|
|
|
241
|
-
fn
|
|
242
|
-
let
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
272
|
+
fn write(target: &str, standalone: bool, mut samples: Vec<Sample>, lengths: &[(usize, usize)], paths: usize, args: &Args) {
|
|
273
|
+
let started = Instant::now();
|
|
274
|
+
samples.sort_unstable_by_key(|s| (s.node_handle, s.node_offset));
|
|
275
|
+
eprintln!("Sorted {} samples in {:.0} s", samples.len(), started.elapsed().as_secs_f64());
|
|
276
|
+
let mut connection = Connection::open(target).unwrap_or_else(|e| {
|
|
277
|
+
eprintln!("Cannot open {}: {}", target, e);
|
|
278
|
+
process::exit(1);
|
|
279
|
+
});
|
|
280
|
+
connection.execute_batch("PRAGMA journal_mode = OFF; PRAGMA synchronous = OFF;").unwrap();
|
|
281
|
+
let mut setup = String::from("DROP TABLE IF EXISTS HaplotypeSamples; DROP TABLE IF EXISTS HaplotypeLengths; ");
|
|
282
|
+
if standalone {
|
|
283
|
+
setup.push_str("CREATE TABLE IF NOT EXISTS Tags (key TEXT PRIMARY KEY, value TEXT NOT NULL) STRICT; ");
|
|
284
|
+
}
|
|
285
|
+
setup.push_str(SCHEMA);
|
|
286
|
+
connection.execute_batch(&setup).unwrap();
|
|
247
287
|
let transaction = connection.transaction().unwrap();
|
|
248
288
|
{
|
|
249
|
-
let mut read_samples = scratch
|
|
250
|
-
.prepare("SELECT node_handle, node_offset, path_handle, orientation, path_offset FROM HaplotypeSamples ORDER BY node_handle, node_offset")
|
|
251
|
-
.unwrap();
|
|
252
289
|
let mut write_sample = transaction
|
|
253
290
|
.prepare("INSERT INTO HaplotypeSamples(node_handle, node_offset, path_handle, orientation, path_offset) VALUES (?1, ?2, ?3, ?4, ?5)")
|
|
254
291
|
.unwrap();
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
292
|
+
for s in samples.iter() {
|
|
293
|
+
write_sample
|
|
294
|
+
.execute(params![s.node_handle as i64, s.node_offset as i64, s.path_handle as i64, s.orientation as i64, s.path_offset as i64])
|
|
295
|
+
.unwrap();
|
|
259
296
|
}
|
|
260
|
-
let mut read_lengths = scratch.prepare("SELECT path_handle, length FROM HaplotypeLengths ORDER BY path_handle").unwrap();
|
|
261
297
|
let mut write_length = transaction.prepare("INSERT INTO HaplotypeLengths(path_handle, length) VALUES (?1, ?2)").unwrap();
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
let handle: i64 = row.get(0).unwrap();
|
|
265
|
-
let length: i64 = row.get(1).unwrap();
|
|
266
|
-
write_length.execute(params![handle, length]).unwrap();
|
|
298
|
+
for &(handle, length) in lengths {
|
|
299
|
+
write_length.execute(params![handle as i64, length as i64]).unwrap();
|
|
267
300
|
}
|
|
268
|
-
transaction
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
.execute(
|
|
273
|
-
"INSERT OR REPLACE INTO Tags(key, value) VALUES ('haplotype_index_orientations', ?1)",
|
|
274
|
-
params![if args.forward_only { "forward" } else { "both" }],
|
|
275
|
-
)
|
|
276
|
-
.unwrap();
|
|
301
|
+
let mut write_tag = transaction.prepare("INSERT OR REPLACE INTO Tags(key, value) VALUES (?1, ?2)").unwrap();
|
|
302
|
+
write_tag.execute(params!["haplotype_index_interval", args.interval.to_string()]).unwrap();
|
|
303
|
+
write_tag.execute(params!["haplotype_index_orientations", if args.forward_only { "forward" } else { "both" }]).unwrap();
|
|
304
|
+
write_tag.execute(params!["haplotype_index_paths", paths.to_string()]).unwrap();
|
|
277
305
|
}
|
|
278
306
|
transaction.commit().unwrap();
|
|
307
|
+
eprintln!("Wrote {} samples for {} paths to {} in {:.0} s", samples.len(), paths, target, started.elapsed().as_secs_f64());
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
fn path_count_from_db(db: &str) -> usize {
|
|
311
|
+
let connection = Connection::open(db).unwrap();
|
|
312
|
+
let value: String = connection
|
|
313
|
+
.query_row("SELECT value FROM Tags WHERE key = 'paths'", [], |row| row.get(0))
|
|
314
|
+
.unwrap_or_else(|_| "0".to_string());
|
|
315
|
+
value.parse().unwrap_or(0)
|
|
279
316
|
}
|
|
280
317
|
|
|
281
318
|
fn main() {
|
|
282
319
|
let args = parse_args();
|
|
283
|
-
let
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
eprintln!("Cannot load {}: {}", gbz, e);
|
|
295
|
-
process::exit(1);
|
|
296
|
-
});
|
|
297
|
-
if graph.metadata().is_none() {
|
|
298
|
-
eprintln!("The GBZ has no path metadata");
|
|
299
|
-
process::exit(1);
|
|
300
|
-
}
|
|
301
|
-
let mut source = GbzSource { graph };
|
|
302
|
-
run(&mut source, &mut scratch, &args);
|
|
320
|
+
let (samples, lengths, paths) = match &args.gbz {
|
|
321
|
+
Some(gbz) => {
|
|
322
|
+
let started = Instant::now();
|
|
323
|
+
let graph: GBZ = serialize::load_from(gbz).unwrap_or_else(|e| {
|
|
324
|
+
eprintln!("Cannot load {}: {}", gbz, e);
|
|
325
|
+
process::exit(1);
|
|
326
|
+
});
|
|
327
|
+
let paths = graph.metadata().map(|m| m.paths()).unwrap_or(0);
|
|
328
|
+
if paths == 0 {
|
|
329
|
+
eprintln!("The GBZ has no path metadata");
|
|
330
|
+
process::exit(1);
|
|
303
331
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
let
|
|
307
|
-
|
|
332
|
+
eprintln!("Loaded {} with {} paths in {:.0} s", gbz, paths, started.elapsed().as_secs_f64());
|
|
333
|
+
if let Some(db) = &args.db {
|
|
334
|
+
let db_paths = path_count_from_db(db);
|
|
335
|
+
if db_paths != paths {
|
|
336
|
+
eprintln!("{} has {} paths but {} has {}", gbz, paths, db, db_paths);
|
|
308
337
|
process::exit(1);
|
|
309
|
-
}
|
|
310
|
-
let interface = GraphInterface::new(&database).unwrap();
|
|
311
|
-
let mut source = DbSource { interface, paths };
|
|
312
|
-
run(&mut source, &mut scratch, &args);
|
|
338
|
+
}
|
|
313
339
|
}
|
|
340
|
+
let (samples, lengths) = walk_gbz(&graph, paths, &args);
|
|
341
|
+
(samples, lengths, paths)
|
|
314
342
|
}
|
|
343
|
+
None => {
|
|
344
|
+
let db = args.db.as_ref().unwrap();
|
|
345
|
+
let paths = path_count_from_db(db);
|
|
346
|
+
let database = GBZBase::open(db).unwrap_or_else(|e| {
|
|
347
|
+
eprintln!("Cannot open {} as a GBZ-base: {}", db, e);
|
|
348
|
+
process::exit(1);
|
|
349
|
+
});
|
|
350
|
+
let interface = GraphInterface::new(&database).unwrap();
|
|
351
|
+
let source = DbSource { interface: std::cell::RefCell::new(interface) };
|
|
352
|
+
let (samples, lengths) = walk_paths(&source, 0..paths, &args, "database walk");
|
|
353
|
+
(samples, lengths, paths)
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
match (&args.output, &args.db) {
|
|
357
|
+
(Some(output), _) => write(output, true, samples, &lengths, paths, &args),
|
|
358
|
+
(None, Some(db)) => write(db, false, samples, &lengths, paths, &args),
|
|
359
|
+
(None, None) => unreachable!(),
|
|
315
360
|
}
|
|
316
|
-
merge(&args.db, &tmp, &args);
|
|
317
|
-
let _ = std::fs::remove_file(&tmp);
|
|
318
|
-
eprintln!("Merged into {}", args.db);
|
|
319
361
|
}
|