1use std::io::Write;
13use std::path::Path;
14
15#[derive(Debug, Clone, Default)]
20pub struct BiasDump {
21 pub obs5_seq: Vec<f64>,
22 pub obs3_seq: Vec<f64>,
23 pub exp5_seq: Vec<f64>,
24 pub exp3_seq: Vec<f64>,
25 pub obs_gc: Vec<f64>,
26 pub exp_gc: Vec<f64>,
27 pub obs5_pos: Vec<Vec<f64>>,
28 pub obs3_pos: Vec<Vec<f64>>,
29 pub exp5_pos: Vec<Vec<f64>>,
30 pub exp3_pos: Vec<Vec<f64>>,
31}
32
33pub fn dump_bias_models_to_file(path: &Path, d: &BiasDump) -> std::io::Result<()> {
38 let mut f = std::io::BufWriter::new(std::fs::File::create(path)?);
39 let flat = |f: &mut std::io::BufWriter<std::fs::File>, name: &str, v: &[f64]| {
40 if v.is_empty() {
41 return Ok(());
42 }
43 write!(f, "{name}")?;
44 for x in v {
45 write!(f, " {x:.6}")?;
46 }
47 writeln!(f)
48 };
49 let per_lc = |f: &mut std::io::BufWriter<std::fs::File>, name: &str, v: &[Vec<f64>]| {
50 for (lc, row) in v.iter().enumerate() {
51 write!(f, "{name} {lc}")?;
52 for x in row {
53 write!(f, " {x:.6}")?;
54 }
55 writeln!(f)?;
56 }
57 Ok::<(), std::io::Error>(())
58 };
59 flat(&mut f, "obs5_seq", &d.obs5_seq)?;
60 flat(&mut f, "obs3_seq", &d.obs3_seq)?;
61 flat(&mut f, "exp5_seq", &d.exp5_seq)?;
62 flat(&mut f, "exp3_seq", &d.exp3_seq)?;
63 flat(&mut f, "obs_gc", &d.obs_gc)?;
64 flat(&mut f, "exp_gc", &d.exp_gc)?;
65 per_lc(&mut f, "obs5_pos", &d.obs5_pos)?;
66 per_lc(&mut f, "obs3_pos", &d.obs3_pos)?;
67 per_lc(&mut f, "exp5_pos", &d.exp5_pos)?;
68 per_lc(&mut f, "exp3_pos", &d.exp3_pos)?;
69 f.flush()
70}
71
72pub fn gz_write(path: &Path, bytes: &[u8]) -> std::io::Result<()> {
74 let f = std::fs::File::create(path)?;
75 let mut enc = flate2::write::GzEncoder::new(f, flate2::Compression::new(6));
76 enc.write_all(bytes)?;
77 enc.finish()?;
78 Ok(())
79}
80
81pub fn write_f64_gz(path: &Path, vals: &[f64]) -> std::io::Result<()> {
83 let mut b = Vec::with_capacity(vals.len() * 8);
84 for v in vals {
85 b.extend_from_slice(&v.to_le_bytes());
86 }
87 gz_write(path, &b)
88}
89
90pub fn write_i32_gz(path: &Path, vals: &[i32]) -> std::io::Result<()> {
92 let mut b = Vec::with_capacity(vals.len() * 4);
93 for v in vals {
94 b.extend_from_slice(&v.to_le_bytes());
95 }
96 gz_write(path, &b)
97}
98
99pub fn write_pos_gz(path: &Path, models: &[Vec<f64>]) -> std::io::Result<()> {
102 let bins = models.first().map(|m| m.len()).unwrap_or(0) as u32;
103 let mut b = Vec::new();
104 b.extend_from_slice(&(models.len() as u32).to_le_bytes());
105 b.extend_from_slice(&bins.to_le_bytes());
106 for m in models {
107 for v in m {
108 b.extend_from_slice(&v.to_le_bytes());
109 }
110 }
111 gz_write(path, &b)
112}
113
114pub fn write_fld_dump(path: &Path, pmf: &[f64]) -> std::io::Result<()> {
118 const N_SAMPLES: f64 = 10000.0;
119 let hist: Vec<i32> = pmf
120 .iter()
121 .map(|&p| (p * N_SAMPLES).round() as i32)
122 .collect();
123 write_i32_gz(path, &hist)
124}
125
126pub fn write_flen_dist(path: &Path, pmf: &[f64]) -> std::io::Result<()> {
129 if let Some(parent) = path.parent() {
130 std::fs::create_dir_all(parent)?;
131 }
132 let mut s = String::with_capacity(pmf.len() * 14);
133 for (i, p) in pmf.iter().enumerate() {
134 if i > 0 {
135 s.push('\t');
136 }
137 s.push_str(&format!("{p:e}"));
138 }
139 s.push('\n');
140 std::fs::write(path, s)
141}
142
143pub fn write_aux_bias_dumps(aux_dir: &Path, dump: &BiasDump) -> std::io::Result<()> {
147 write_i32_gz(&aux_dir.join("observed_bias.gz"), &[0])?;
149 write_i32_gz(&aux_dir.join("observed_bias_3p.gz"), &[0])?;
150 write_f64_gz(&aux_dir.join("expected_bias.gz"), &[1.0])?;
151
152 if !dump.obs5_seq.is_empty() {
153 write_f64_gz(&aux_dir.join("obs5_seq.gz"), &dump.obs5_seq)?;
154 write_f64_gz(&aux_dir.join("obs3_seq.gz"), &dump.obs3_seq)?;
155 write_f64_gz(&aux_dir.join("exp5_seq.gz"), &dump.exp5_seq)?;
156 write_f64_gz(&aux_dir.join("exp3_seq.gz"), &dump.exp3_seq)?;
157 }
158 if !dump.obs_gc.is_empty() {
159 write_f64_gz(&aux_dir.join("obs_gc.gz"), &dump.obs_gc)?;
160 write_f64_gz(&aux_dir.join("exp_gc.gz"), &dump.exp_gc)?;
161 }
162 if !dump.obs5_pos.is_empty() {
163 write_pos_gz(&aux_dir.join("obs5_pos.gz"), &dump.obs5_pos)?;
164 write_pos_gz(&aux_dir.join("obs3_pos.gz"), &dump.obs3_pos)?;
165 write_pos_gz(&aux_dir.join("exp5_pos.gz"), &dump.exp5_pos)?;
166 write_pos_gz(&aux_dir.join("exp3_pos.gz"), &dump.exp3_pos)?;
167 }
168 Ok(())
169}