scran_qc
Simple quality control on single-cell data
Loading...
Searching...
No Matches
crispr_quality_control.hpp
Go to the documentation of this file.
1#ifndef SCRAN_QC_CRISPR_QUALITY_CONTROL_HPP
2#define SCRAN_QC_CRISPR_QUALITY_CONTROL_HPP
3
4#include <vector>
5#include <limits>
6#include <algorithm>
7#include <type_traits>
8#include <cstddef>
9
10#include "tatami/tatami.hpp"
11#include "sanisizer/sanisizer.hpp"
12#include "quickstats/quickstats.hpp"
13
16#include "utils.hpp"
17
23namespace scran_qc {
24
35
48template<typename Sum_ = double, typename Detected_ = int, typename Value_ = double, typename Index_ = int>
55 Sum_* sum;
56
62 Detected_* detected;
63
69 Value_* max_value;
70
75 Index_* max_index;
76};
77
105template<typename Value_, typename Index_, typename Sum_, typename Detected_>
109 const ComputeCrisprQcMetricsOptions& options)
110{
112 tmp.sum = output.sum;
113 tmp.detected = output.detected;
114 tmp.max_value = output.max_value;
115 tmp.max_index = output.max_index;
116
118 opt.num_threads = options.num_threads;
119 per_cell_qc_metrics(mat, std::vector<const unsigned char*>{}, tmp, opt);
120}
121
134template<typename Sum_ = double, typename Detected_ = int, typename Value_ = double, typename Index_ = int>
140 std::vector<Sum_> sum;
141
146 std::vector<Detected_> detected;
147
152 std::vector<Value_> max_value;
153
157 std::vector<Index_> max_index;
158};
159
177template<typename Sum_ = double, typename Detected_ = int, typename Value_ = double, typename Index_ = int>
180 const ComputeCrisprQcMetricsOptions& options)
181{
182 const auto NC = mat.ncol();
185
187#ifdef SCRAN_QC_TEST_INIT
188 , SCRAN_QC_TEST_INIT
189#endif
190 );
191 x.sum = output.sum.data();
192
194#ifdef SCRAN_QC_TEST_INIT
195 , SCRAN_QC_TEST_INIT
196#endif
197 );
198 x.detected = output.detected.data();
199
201#ifdef SCRAN_QC_TEST_INIT
202 , SCRAN_QC_TEST_INIT
203#endif
204 );
205 x.max_value = output.max_value.data();
206
208#ifdef SCRAN_QC_TEST_INIT
209 , SCRAN_QC_TEST_INIT
210#endif
211 );
212 x.max_index = output.max_index.data();
213
214 compute_crispr_qc_metrics(mat, x, options);
215 return output;
216}
217
228
232template<typename Float_, class Host_, typename Sum_, typename Detected_, typename Value_, typename Index_, typename BlockSource_>
233void compute_crispr_qc_filters_internal(
234 Host_& host,
235 const std::size_t num_cells,
237 BlockSource_ block,
238 const std::size_t num_blocks,
239 const ComputeCrisprQcFiltersOptions& options
240) {
241 constexpr bool unblocked = std::is_same<BlockSource_, bool>::value;
242 auto buffer = [&]{
243 if constexpr(unblocked) {
244 return sanisizer::create<std::vector<Float_> >(num_cells);
245 } else {
246 return ChooseFilterThresholdsBlockedWorkspace<Float_>(num_cells, block, num_blocks);
247 }
248 }();
249
250 // Subsetting to the observations in the top 50% of proportions.
251 static_assert(std::is_floating_point<Float_>::value);
252 std::vector<Float_> maxprop;
253 maxprop.reserve(num_cells);
254 for (I<decltype(num_cells)> i = 0; i < num_cells; ++i) {
255 maxprop.push_back(static_cast<Float_>(res.max_value[i]) / static_cast<Float_>(res.sum[i]));
256 }
257
258 auto prop_res = [&]{
259 quickstats::MedianOptions<Float_> medopt;
260 medopt.placeholder = std::numeric_limits<Float_>::quiet_NaN();
261
262 if constexpr(unblocked) {
263 std::copy_n(maxprop.begin(), num_cells, buffer.begin());
264 return quickstats::median<Float_>(num_cells, buffer.data(), medopt);
265 } else {
266 std::vector<Float_> output;
267 output.reserve(num_blocks);
268 process_blocks_for_choose_filter_thresholds(
269 num_cells,
270 maxprop.data(),
271 block,
272 num_blocks,
273 buffer,
274 [&](const std::size_t len, Float_* const ptr) -> void {
275 output.push_back(quickstats::median<Float_>(len, ptr, medopt));
276 }
277 );
278 return output;
279 }
280 }();
281
282 for (I<decltype(num_cells)> i = 0; i < num_cells; ++i) {
283 auto limit = [&]{
284 if constexpr(unblocked){
285 return prop_res;
286 } else {
287 return prop_res[block[i]];
288 }
289 }();
290 if (maxprop[i] >= limit) {
291 maxprop[i] = res.max_value[i];
292 } else {
293 maxprop[i] = std::numeric_limits<Float_>::quiet_NaN(); // ignored during threshold calculation.
294 }
295 }
296
297 // Filtering on the max counts.
298 ChooseFilterThresholdsOptions copt;
299 copt.num_mads = options.max_value_num_mads;
300 copt.log = true;
301 copt.upper = false;
302 host.get_max_value() = [&]{
303 if constexpr(unblocked) {
304 return choose_filter_thresholds(num_cells, maxprop.data(), buffer.data(), copt).lower;
305 } else {
306 return extract_filter_thresholds<true>(choose_filter_thresholds_blocked(num_cells, maxprop.data(), block, num_blocks, buffer, copt));
307 }
308 }();
309}
310
311template<class Host_, typename Sum_, typename Detected_, typename Value_, typename Index_, typename BlockSource_, typename Output_>
312void apply_crispr_qc_filters_internal(
313 const Host_& host,
314 const std::size_t n,
315 const ComputeCrisprQcMetricsBuffers<Sum_, Detected_, Value_, Index_>& metrics,
316 BlockSource_ block,
317 Output_* const output
318) {
319 constexpr bool unblocked = std::is_same<BlockSource_, bool>::value;
320 std::fill_n(output, n, 1);
321
322 const auto& mv = host.get_max_value();
323 for (I<decltype(n)> i = 0; i < n; ++i) {
324 auto thresh = [&]{
325 if constexpr(unblocked) {
326 return mv;
327 } else {
328 return mv[block[i]];
329 }
330 }();
331 output[i] = output[i] && (metrics.max_value[i] >= thresh);
332 }
333}
334
335template<typename Sum_, typename Detected_, typename Value_, typename Index_>
336ComputeCrisprQcMetricsBuffers<const Sum_, const Detected_, const Value_, const Index_> crispr_qc_results_to_buffers(const ComputeCrisprQcMetricsResults<Sum_, Detected_, Value_, Index_>& metrics) {
337 ComputeCrisprQcMetricsBuffers<const Sum_, const Detected_, const Value_, const Index_> buffer;
338 buffer.sum = metrics.sum.data();
339 buffer.detected = metrics.detected.data();
340 buffer.max_value = metrics.max_value.data();
341 buffer.max_index = metrics.max_index.data();
342 return buffer;
343}
354template<typename Float_ = double>
356public:
360 Float_ get_max_value() const {
361 return my_max_value;
362 }
363
367 Float_& get_max_value() {
368 return my_max_value;
369 }
370
371private:
372 Float_ my_max_value = 0;
373
374public:
387 template<typename Sum_, typename Detected_, typename Value_, typename Index_, typename Output_>
388 void filter(const std::size_t num_cells, const ComputeCrisprQcMetricsBuffers<Sum_, Detected_, Value_, Index_>& metrics, Output_* const output) const {
389 apply_crispr_qc_filters_internal(*this, num_cells, metrics, false, output);
390 }
391
403 template<typename Sum_, typename Detected_, typename Value_, typename Index_, typename Output_>
404 void filter(const ComputeCrisprQcMetricsResults<Sum_, Detected_, Value_, Index_>& metrics, Output_* const output) const {
405 return filter(metrics.max_value.size(), crispr_qc_results_to_buffers(metrics), output);
406 }
407
418 template<typename Output_ = unsigned char, typename Sum_, typename Detected_, typename Value_, typename Index_>
420 auto output = sanisizer::create<std::vector<Output_> >(metrics.max_value.size()
421#ifdef SCRAN_QC_TEST_INIT
422 , SCRAN_QC_TEST_INIT
423#endif
424 );
425 filter(metrics, output.data());
426 return output;
427 }
428};
429
463template<typename Float_ = double, typename Sum_, typename Detected_, typename Value_, typename Index_>
465 const std::size_t num_cells,
467 const ComputeCrisprQcFiltersOptions& options)
468{
470 compute_crispr_qc_filters_internal<Float_>(output, num_cells, metrics, false, 0, options);
471 return output;
472}
473
486template<typename Float_ = double, typename Sum_, typename Detected_, typename Value_, typename Index_>
489 const ComputeCrisprQcFiltersOptions& options)
490{
491 return compute_crispr_qc_filters(metrics.max_value.size(), crispr_qc_results_to_buffers(metrics), options);
492}
493
499template<typename Float_ = double>
501public:
506 const std::vector<Float_>& get_max_value() const {
507 return my_max_value;
508 }
509
514 std::vector<Float_>& get_max_value() {
515 return my_max_value;
516 }
517
518private:
519 std::vector<Float_> my_sum;
520 std::vector<Float_> my_max_value;
521
522public:
538 template<typename Sum_, typename Detected_, typename Value_, typename Index_, typename Block_, typename Output_>
539 void filter(const std::size_t num_cells, const ComputeCrisprQcMetricsBuffers<Sum_, Detected_, Value_, Index_>& metrics, const Block_* const block, Output_* const output) const {
540 apply_crispr_qc_filters_internal(*this, num_cells, metrics, block, output);
541 }
542
557 template<typename Sum_, typename Detected_, typename Value_, typename Index_, typename Block_, typename Output_>
558 void filter(const ComputeCrisprQcMetricsResults<Sum_, Detected_, Value_, Index_>& metrics, const Block_* const block, Output_* const output) const {
559 filter(metrics.max_value.size(), crispr_qc_results_to_buffers(metrics), block, output);
560 }
561
576 template<typename Output_ = unsigned char, typename Sum_, typename Detected_, typename Value_, typename Index_, typename Block_>
577 std::vector<Output_> filter(const ComputeCrisprQcMetricsResults<Sum_, Detected_, Value_, Index_>& metrics, const Block_* const block) const {
578 auto output = sanisizer::create<std::vector<Output_> >(metrics.max_value.size()
579#ifdef SCRAN_QC_TEST_INIT
580 , SCRAN_QC_TEST_INIT
581#endif
582 );
583 filter(metrics, block, output.data());
584 return output;
585 }
586};
587
608template<typename Float_ = double, typename Sum_, typename Detected_, typename Value_, typename Index_, typename Block_>
610 const std::size_t num_cells,
612 const Block_* const block,
613 const std::size_t num_blocks,
614 const ComputeCrisprQcFiltersOptions& options
615) {
617 compute_crispr_qc_filters_internal<Float_>(output, num_cells, metrics, block, num_blocks, options);
618 return output;
619}
620
636template<typename Float_ = double, typename Sum_, typename Detected_, typename Value_, typename Index_, typename Block_>
639 const Block_* const block,
640 const std::size_t num_blocks,
641 const ComputeCrisprQcFiltersOptions& options
642) {
643 return compute_crispr_qc_filters_blocked(metrics.max_value.size(), crispr_qc_results_to_buffers(metrics), block, num_blocks, options);
644}
645
646}
647
648#endif
Define QC filter thresholds using a MAD-based approach.
Filter on using CRISPR-based QC metrics with blocking.
Definition crispr_quality_control.hpp:500
std::vector< Float_ > & get_max_value()
Definition crispr_quality_control.hpp:514
void filter(const ComputeCrisprQcMetricsResults< Sum_, Detected_, Value_, Index_ > &metrics, const Block_ *const block, Output_ *const output) const
Definition crispr_quality_control.hpp:558
void filter(const std::size_t num_cells, const ComputeCrisprQcMetricsBuffers< Sum_, Detected_, Value_, Index_ > &metrics, const Block_ *const block, Output_ *const output) const
Definition crispr_quality_control.hpp:539
const std::vector< Float_ > & get_max_value() const
Definition crispr_quality_control.hpp:506
std::vector< Output_ > filter(const ComputeCrisprQcMetricsResults< Sum_, Detected_, Value_, Index_ > &metrics, const Block_ *const block) const
Definition crispr_quality_control.hpp:577
Filter for high-quality cells using CRISPR-based metrics.
Definition crispr_quality_control.hpp:355
std::vector< Output_ > filter(const ComputeCrisprQcMetricsResults< Sum_, Detected_, Value_, Index_ > &metrics) const
Definition crispr_quality_control.hpp:419
Float_ get_max_value() const
Definition crispr_quality_control.hpp:360
Float_ & get_max_value()
Definition crispr_quality_control.hpp:367
void filter(const ComputeCrisprQcMetricsResults< Sum_, Detected_, Value_, Index_ > &metrics, Output_ *const output) const
Definition crispr_quality_control.hpp:404
void filter(const std::size_t num_cells, const ComputeCrisprQcMetricsBuffers< Sum_, Detected_, Value_, Index_ > &metrics, Output_ *const output) const
Definition crispr_quality_control.hpp:388
virtual Index_ ncol() const=0
Simple quality control for single-cell data.
Definition adt_quality_control.hpp:22
std::vector< ChooseFilterThresholdsResults< Float_ > > choose_filter_thresholds_blocked(const std::size_t num_cells, const Value_ *const metrics, const Block_ *const block, const std::size_t num_blocks, ChooseFilterThresholdsBlockedWorkspace< Float_ > &workspace, const ChooseFilterThresholdsOptions &options)
Definition choose_filter_thresholds.hpp:333
ChooseFilterThresholdsResults< Float_ > choose_filter_thresholds(const std::size_t num_cells, const Value_ *const metrics, Float_ *const buffer, const ChooseFilterThresholdsOptions &options)
Definition choose_filter_thresholds.hpp:200
void compute_crispr_qc_metrics(const tatami::Matrix< Value_, Index_ > &mat, const ComputeCrisprQcMetricsBuffers< Sum_, Detected_, Value_, Index_ > &output, const ComputeCrisprQcMetricsOptions &options)
Definition crispr_quality_control.hpp:106
CrisprQcFilters< Float_ > compute_crispr_qc_filters(const std::size_t num_cells, const ComputeCrisprQcMetricsBuffers< Sum_, Detected_, Value_, Index_ > &metrics, const ComputeCrisprQcFiltersOptions &options)
Definition crispr_quality_control.hpp:464
CrisprQcBlockedFilters< Float_ > compute_crispr_qc_filters_blocked(const std::size_t num_cells, const ComputeCrisprQcMetricsBuffers< Sum_, Detected_, Value_, Index_ > &metrics, const Block_ *const block, const std::size_t num_blocks, const ComputeCrisprQcFiltersOptions &options)
Definition crispr_quality_control.hpp:609
void per_cell_qc_metrics(const tatami::Matrix< Value_, Index_ > &mat, const std::vector< Subset_ > &subsets, const PerCellQcMetricsBuffers< Sum_, Detected_, Value_, Index_ > &output, const PerCellQcMetricsOptions &options)
Definition per_cell_qc_metrics.hpp:1001
void resize_container_to_Index_size(Container_ &container, const Index_ x, Args_ &&... args)
Compute per-cell quality control metrics.
Workspace for choose_filter_thresholds_blocked().
Definition choose_filter_thresholds.hpp:226
Options for compute_crispr_qc_filters().
Definition crispr_quality_control.hpp:221
double max_value_num_mads
Definition crispr_quality_control.hpp:226
Buffers for compute_crispr_qc_metrics().
Definition crispr_quality_control.hpp:49
Sum_ * sum
Definition crispr_quality_control.hpp:55
Detected_ * detected
Definition crispr_quality_control.hpp:62
Index_ * max_index
Definition crispr_quality_control.hpp:75
Value_ * max_value
Definition crispr_quality_control.hpp:69
Options for compute_crispr_qc_metrics().
Definition crispr_quality_control.hpp:28
int num_threads
Definition crispr_quality_control.hpp:33
Results of compute_crispr_qc_metrics().
Definition crispr_quality_control.hpp:135
std::vector< Index_ > max_index
Definition crispr_quality_control.hpp:157
std::vector< Value_ > max_value
Definition crispr_quality_control.hpp:152
std::vector< Detected_ > detected
Definition crispr_quality_control.hpp:146
std::vector< Sum_ > sum
Definition crispr_quality_control.hpp:140
Buffers for per_cell_qc_metrics().
Definition per_cell_qc_metrics.hpp:97
Value_ * max_value
Definition per_cell_qc_metrics.hpp:127
Index_ * max_index
Definition per_cell_qc_metrics.hpp:134
Sum_ * sum
Definition per_cell_qc_metrics.hpp:115
Detected_ * detected
Definition per_cell_qc_metrics.hpp:121
Options for per_cell_qc_metrics().
Definition per_cell_qc_metrics.hpp:25
int num_threads
Definition per_cell_qc_metrics.hpp:83