use super::*;
use crate::sparse_io::open_sparse_matrix;
use crate::zarr_io::apply_zip_flag;
use hdf5::types::VarLenUnicode;
fn strings(g: &hdf5::Group, name: &str, xs: &[&str]) {
let v: Vec<VarLenUnicode> = xs.iter().map(|s| s.parse().unwrap()).collect();
g.new_dataset_builder().with_data(&v).create(name).unwrap();
}
fn molecule_info(path: &std::path::Path, probe_set: Option<&str>) {
let f = hdf5::File::create(path).unwrap();
let features = f.create_group("features").unwrap();
strings(&features, "id", &["FID1", "FID2", "FID3"]);
strings(&features, "name", &["GENE1", "GENE2", "GENE3"]);
strings(&features, "feature_type", &["Gene Expression"; 3]);
strings(&f, "barcodes", &["AAAC", "AAAG", "AAAT", "AACA"]);
let target = match probe_set {
Some(name) => {
features
.create_group("target_sets")
.unwrap()
.new_dataset_builder()
.with_data(&[0u32, 2])
.create(name)
.unwrap();
format!(r#", "target_set_name": "{name}""#)
}
None => String::new(),
};
let libraries = format!(
r#"[{{"gem_group": 1, "library_id": "0", "library_type": "Gene Expression"{target}}},
{{"gem_group": 1, "library_id": 1, "library_type": "Antibody Capture"}}]"#
);
strings(&f, "library_info", &[&libraries]);
let column = |name: &str, v: &[u64]| {
f.new_dataset_builder().with_data(v).create(name).unwrap();
};
let m: [[u64; 5]; 6] = [
[0, 0, 3, 0, 1],
[0, 0, 2, 0, 1],
[0, 1, 4, 0, 0], [1, 1, 1, 0, 1],
[1, 0, 7, 1, 1], [2, 0, 1, 0, 1], ];
let col = |j: usize| m.iter().map(|r| r[j]).collect::<Vec<_>>();
column("barcode_idx", &col(0));
column("feature_idx", &col(1));
column("count", &col(2));
column("library_idx", &col(3));
column("umi_type", &col(4));
column("gem_group", &[1; 6]);
let cells = ndarray::arr2(&[[0u64, 0, 0], [1, 0, 0], [1, 1, 0], [3, 0, 0]]);
f.create_group("barcode_info")
.unwrap()
.new_dataset_builder()
.with_data(&cells)
.create("pass_filter")
.unwrap();
}
struct Written {
rows: Vec<Box<str>>,
columns: Vec<Box<str>>,
values: Vec<Vec<f32>>,
}
fn read(h5: &std::path::Path, out: &std::path::Path, sum_reads: bool) -> Written {
let args = From10xMoleculeArgs {
h5_file: h5.to_str().unwrap().into(),
backend: SparseIoBackend::Zarr,
output: out.to_str().unwrap().into(),
zip: true,
library_type: "Gene Expression".into(),
select_row_type: "".into(),
remove_row_type: "".into(),
no_pass_filter: false,
sum_reads,
do_squeeze: false,
row_nnz_cutoff: 1,
column_nnz_cutoff: 1,
block_size: None,
view: crate::handlers::explore::PlanArgs::batch(),
};
run_build_from_10x_molecule(&args).unwrap();
let data = open_sparse_matrix(
&apply_zip_flag(&args.output, true, &SparseIoBackend::Zarr),
&SparseIoBackend::Zarr,
)
.unwrap();
let m = data
.read_columns_dmatrix((0..data.num_columns().unwrap()).collect())
.unwrap();
Written {
rows: data.row_names().unwrap(),
columns: data.column_names().unwrap(),
values: m.row_iter().map(|r| r.iter().copied().collect()).collect(),
}
}
#[test]
fn molecules_count_as_cell_ranger_counts_them() {
let dir = tempfile::tempdir().unwrap();
let h5 = dir.path().join("molecule_info.h5");
molecule_info(&h5, None);
let umis = read(&h5, &dir.path().join("umis"), false);
assert_eq!(
umis.rows,
["FID1_GENE1", "FID2_GENE2", "FID3_GENE3"].map(Box::from)
);
assert_eq!(umis.columns, ["AAAC-1", "AAAG-1", "AACA-1"].map(Box::from));
assert_eq!(umis.values, [[2., 0., 0.], [0., 1., 0.], [0., 0., 0.]]);
let reads = read(&h5, &dir.path().join("reads"), true);
assert_eq!(reads.values, [[5., 0., 0.], [0., 1., 0.], [0., 0., 0.]]);
}
#[test]
fn a_probe_based_library_counts_the_genes_its_probes_target() {
let dir = tempfile::tempdir().unwrap();
let h5 = dir.path().join("molecule_info.h5");
molecule_info(&h5, Some("SET1"));
let umis = read(&h5, &dir.path().join("umis"), false);
assert_eq!(umis.rows, ["FID1_GENE1", "FID3_GENE3"].map(Box::from));
assert_eq!(umis.columns, ["AAAC-1", "AAAG-1", "AACA-1"].map(Box::from));
assert_eq!(umis.values, [[2., 0., 0.], [0., 0., 0.]]);
}