• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MikkelSchubert / adapterremoval / #45

20 Sep 2024 06:49PM UTC coverage: 26.244% (-49.2%) from 75.443%
#45

push

travis-ci

web-flow
attempt to fix coveralls run

2458 of 9366 relevant lines covered (26.24%)

4362.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/demultiplexing.cpp
1
/*************************************************************************\
2
 * AdapterRemoval - cleaning next-generation sequencing reads            *
3
 *                                                                       *
4
 * Copyright (C) 2021 by Stinus Lindgreen - stinus@binf.ku.dk            *
5
 * Copyright (C) 2014 by Mikkel Schubert - mikkelsch@gmail.com           *
6
 *                                                                       *
7
 * This program is free software: you can redistribute it and/or modify  *
8
 * it under the terms of the GNU General Public License as published by  *
9
 * the Free Software Foundation, either version 3 of the License, or     *
10
 * (at your option) any later version.                                   *
11
 *                                                                       *
12
 * This program is distributed in the hope that it will be useful,       *
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15
 * GNU General Public License for more details.                          *
16
 *                                                                       *
17
 * You should have received a copy of the GNU General Public License     *
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
19
\*************************************************************************/
20
#include "demultiplexing.hpp"
21
#include "barcode_table.hpp" // for barcode_table
22
#include "debug.hpp"         // for AR_REQUIRE, AR_REQUIRE_SINGLE_THREAD
23
#include "fastq_io.hpp"      // for chunk_ptr, fastq...
24
#include "output.hpp"        // for output_files
25
#include "sequence_sets.hpp" // for adapter_set
26
#include "serializer.hpp"    // for fastq_flags
27
#include "userconfig.hpp"    // for userconfig, ar_command, ar_command::demul...
28
#include <cstddef>           // for size_t
29
#include <memory>            // for make_unique, unique_ptr
30
#include <utility>           // for move
31

32
namespace adapterremoval {
33

34
///////////////////////////////////////////////////////////////////////////////
35
// Implementations for `demultiplex_reads`
36

37
demultiplex_reads::demultiplex_reads(const userconfig& config,
×
38
                                     const post_demux_steps& steps,
39
                                     demux_stats_ptr stats)
×
40
  : analytical_step(processing_order::ordered, "demultiplex_reads")
41
  , m_samples(config.samples)
×
42
  , m_barcode_table(m_samples,
×
43
                    config.barcode_mm,
×
44
                    config.barcode_mm_r1,
×
45
                    config.barcode_mm_r2)
×
46
  , m_config(config)
×
47
  , m_steps(steps)
×
48
  , m_cache(steps)
×
49
  , m_statistics(std::move(stats))
×
50
{
51
  AR_REQUIRE(m_samples.size());
×
52
  AR_REQUIRE(m_samples.size() == m_steps.samples.size());
×
53
  AR_REQUIRE(m_statistics);
×
54
  AR_REQUIRE(m_statistics->samples.size() == m_samples.size());
×
55

56
  // Map global barcode offsets to sample and relative barcode offsets
57
  for (size_t i = 0; i < m_samples.size(); ++i) {
×
58
    const size_t barcodes = m_samples.at(i).size();
×
59
    for (size_t j = 0; j < barcodes; ++j) {
×
60
      m_barcodes.emplace_back(i, j);
×
61
    }
62
  }
63
}
64

65
///////////////////////////////////////////////////////////////////////////////
66

67
demultiplex_se_reads::demultiplex_se_reads(const userconfig& config,
×
68
                                           const post_demux_steps& steps,
69
                                           demux_stats_ptr stats)
×
70
  : demultiplex_reads(config, steps, std::move(stats))
×
71
{
72
}
73

74
chunk_vec
75
demultiplex_se_reads::process(chunk_ptr chunk)
×
76
{
77
  AR_REQUIRE(chunk);
×
78
  AR_REQUIRE_SINGLE_THREAD(m_lock);
×
79
  for (auto& read : chunk->reads_1) {
×
80
    const auto match = m_barcode_table.identify(read);
×
81

82
    if (match < 0) {
×
83
      switch (match) {
×
84
        case barcode_table::no_match:
×
85
          m_statistics->unidentified += 1;
×
86
          break;
×
87
        case barcode_table::ambiguous:
×
88
          m_statistics->ambiguous += 1;
×
89
          break;
×
90
        default:
×
91
          AR_FAIL("invalid barcode match sample");
×
92
      }
93

94
      m_cache.add_unidentified_1(std::move(read));
×
95
    } else {
96
      const auto [sample, barcode] = m_barcodes.at(match);
×
97

98
      read.truncate(m_barcode_table.length_1());
×
99

100
      m_statistics->samples.at(sample) += 1;
×
101
      m_cache.add_read_1(std::move(read), sample, barcode);
×
102
    }
103
  }
104

105
  return m_cache.flush(chunk->eof, chunk->mate_separator);
×
106
}
107

108
///////////////////////////////////////////////////////////////////////////////
109

110
demultiplex_pe_reads::demultiplex_pe_reads(const userconfig& config,
×
111
                                           const post_demux_steps& steps,
112
                                           demux_stats_ptr stats)
×
113
  : demultiplex_reads(config, steps, std::move(stats))
×
114
{
115
}
116

117
chunk_vec
118
demultiplex_pe_reads::process(chunk_ptr chunk)
×
119
{
120
  AR_REQUIRE(chunk);
×
121
  AR_REQUIRE_SINGLE_THREAD(m_lock);
×
122
  AR_REQUIRE(chunk->reads_1.size() == chunk->reads_2.size());
×
123

124
  auto it_1 = chunk->reads_1.begin();
×
125
  auto it_2 = chunk->reads_2.begin();
×
126
  for (; it_1 != chunk->reads_1.end(); ++it_1, ++it_2) {
×
127
    const auto match = m_barcode_table.identify(*it_1, *it_2);
×
128

129
    if (match < 0) {
×
130
      switch (match) {
×
131
        case barcode_table::no_match:
×
132
          m_statistics->unidentified += 2;
×
133
          break;
×
134
        case barcode_table::ambiguous:
×
135
          m_statistics->ambiguous += 2;
×
136
          break;
×
137
        default:
×
138
          AR_FAIL("invalid barcode match sample");
×
139
      }
140

141
      m_cache.add_unidentified_1(std::move(*it_1));
×
142
      m_cache.add_unidentified_2(std::move(*it_2));
×
143
    } else {
144
      const auto [sample, barcode] = m_barcodes.at(match);
×
145

146
      it_1->truncate(m_barcode_table.length_1());
×
147
      m_cache.add_read_1(std::move(*it_1), sample, barcode);
×
148

149
      it_2->truncate(m_barcode_table.length_2());
×
150
      m_cache.add_read_2(std::move(*it_2), sample);
×
151

152
      m_statistics->samples.at(sample) += 2;
×
153
    }
154
  }
155

156
  return m_cache.flush(chunk->eof, chunk->mate_separator);
×
157
}
158

159
///////////////////////////////////////////////////////////////////////////////
160

161
process_demultiplexed::process_demultiplexed(const userconfig& config,
×
162
                                             const sample_output_files& output,
163
                                             const size_t sample,
164
                                             trim_stats_ptr sink)
×
165
  : analytical_step(processing_order::unordered, "process_demultiplexed")
166
  , m_config(config)
×
167
  , m_output(output)
×
168
  , m_samples(config.samples)
×
169
  , m_sample(sample)
×
170
  , m_stats_sink(std::move(sink))
×
171
{
172
  m_stats.emplace_back_n(m_config.max_threads, m_config.report_sample_rate);
×
173
}
174

175
chunk_vec
176
process_demultiplexed::process(chunk_ptr chunk)
×
177
{
178
  AR_REQUIRE(chunk);
×
179
  processed_reads chunks{ m_output };
×
180
  chunks.set_sample(m_samples.at(m_sample));
×
181
  chunks.set_mate_separator(chunk->mate_separator);
×
182
  chunks.set_demultiplexing_only(true);
×
183

184
  if (chunk->first) {
×
185
    chunks.write_headers(m_config.args);
×
186
  }
187

188
  auto stats = m_stats.acquire();
×
189

190
  AR_REQUIRE(chunk->reads_1.size() == chunk->barcodes.size());
×
191
  auto barcode = chunk->barcodes.begin();
×
192

193
  if (m_config.paired_ended_mode) {
×
194
    AR_REQUIRE(chunk->reads_1.size() == chunk->reads_2.size());
×
195

196
    auto it_1 = chunk->reads_1.begin();
×
197
    auto it_2 = chunk->reads_2.begin();
×
198
    for (; it_1 != chunk->reads_1.end(); ++it_1, ++it_2, ++barcode) {
×
199
      it_1->add_prefix_to_name(m_config.prefix_read_1);
×
200
      stats->read_1->process(*it_1);
×
201
      chunks.add(*it_1, read_type::mate_1, fastq_flags::pe_1, *barcode);
×
202

203
      it_2->add_prefix_to_name(m_config.prefix_read_2);
×
204
      stats->read_2->process(*it_2);
×
205
      chunks.add(*it_2, read_type::mate_2, fastq_flags::pe_2, *barcode);
×
206
    }
207
  } else {
208
    for (auto& read : chunk->reads_1) {
×
209
      read.add_prefix_to_name(m_config.prefix_read_1);
×
210

211
      stats->read_1->process(read);
×
212
      chunks.add(read, read_type::mate_1, fastq_flags::se, *barcode++);
×
213
    }
214
  }
215

216
  m_stats.release(stats);
×
217

218
  return chunks.finalize(chunk->eof);
×
219
}
220

221
void
222
process_demultiplexed::finalize()
×
223
{
224
  m_stats.merge_into(*m_stats_sink);
×
225
}
226

227
///////////////////////////////////////////////////////////////////////////////
228

229
processes_unidentified::processes_unidentified(const userconfig& config,
×
230
                                               const output_files& output,
231
                                               demux_stats_ptr stats)
×
232
  : analytical_step(processing_order::unordered, "processes_unidentified")
233
  , m_config(config)
×
234
  , m_statistics(std::move(stats))
×
235
{
236
  m_output.set_file(read_type::mate_1, output.unidentified_1);
×
237
  m_output.set_file(read_type::mate_2, output.unidentified_2);
×
238

239
  m_output.set_step(read_type::mate_1, output.unidentified_1_step);
×
240
  if (output.unidentified_1_step != output.unidentified_2_step &&
×
241
      output.unidentified_2_step != output_files::disabled) {
×
242
    m_output.set_step(read_type::mate_2, output.unidentified_2_step);
×
243
  }
244

245
  m_stats_1.emplace_back_n(m_config.max_threads, config.report_sample_rate);
×
246
  m_stats_2.emplace_back_n(m_config.max_threads, config.report_sample_rate);
×
247
}
248

249
chunk_vec
250
processes_unidentified::process(chunk_ptr chunk)
×
251
{
252
  AR_REQUIRE(chunk);
×
253
  processed_reads chunks{ m_output };
×
254
  chunks.set_sample(m_config.samples.unidentified());
×
255
  chunks.set_mate_separator(chunk->mate_separator);
×
256

257
  if (chunk->first) {
×
258
    chunks.write_headers(m_config.args);
×
259
  }
260

261
  auto stats_1 = m_stats_1.acquire();
×
262
  auto stats_2 = m_stats_2.acquire();
×
263

264
  if (m_config.paired_ended_mode) {
×
265
    AR_REQUIRE(chunk->reads_1.size() == chunk->reads_2.size());
×
266

267
    auto it_1 = chunk->reads_1.begin();
×
268
    auto it_2 = chunk->reads_2.begin();
×
269

270
    for (; it_1 != chunk->reads_1.end(); ++it_1, ++it_2) {
×
271
      it_1->add_prefix_to_name(m_config.prefix_read_1);
×
272
      stats_1->process(*it_1);
×
273
      chunks.add(*it_1, read_type::mate_1, fastq_flags::pe_1, 0);
×
274

275
      it_2->add_prefix_to_name(m_config.prefix_read_2);
×
276
      stats_2->process(*it_2);
×
277
      chunks.add(*it_2, read_type::mate_2, fastq_flags::pe_2, 0);
×
278
    }
279
  } else {
280
    for (auto& read : chunk->reads_1) {
×
281
      read.add_prefix_to_name(m_config.prefix_read_1);
×
282

283
      stats_1->process(read);
×
284
      chunks.add(read, read_type::mate_1, fastq_flags::se, 0);
×
285
    }
286
  }
287

288
  m_stats_1.release(stats_1);
×
289
  m_stats_2.release(stats_2);
×
290

291
  return chunks.finalize(chunk->eof);
×
292
}
293

294
void
295
processes_unidentified::finalize()
×
296
{
297
  m_stats_1.merge_into(*m_statistics->unidentified_stats_1);
×
298
  m_stats_2.merge_into(*m_statistics->unidentified_stats_2);
×
299
}
300

301
} // namespace adapterremoval
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc