--- title: "A native SeuratObject v5 workflow" author: "Yaoxiang Li" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{A native SeuratObject v5 workflow} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = requireNamespace("SeuratObject", quietly = TRUE) ) ``` `cudacell_seurat()` runs the complete cudacellr preprocessing, PCA, and exact nearest-neighbour workflow while keeping every result in a native Seurat v5 subobject. The adapter requires only `SeuratObject >= 5.0.0`; installing the full Seurat package is not necessary. ```{r install, eval=FALSE} install.packages("SeuratObject") ``` ## Start with a populated object This example contains a second assay, cell metadata, identities, a reduction, miscellaneous data, and a tool record. The workflow returns a modified copy and retains all of them. ```{r fixture} library(cudacellr) library(Matrix) set.seed(42) counts <- Matrix( matrix( rpois(80 * 30, lambda = 2), nrow = 80, dimnames = list( paste0("gene_", seq_len(80)), paste0("cell_", seq_len(30)) ) ), sparse = TRUE ) counts[1, ] <- counts[1, ] + 1 object <- SeuratObject::CreateSeuratObject( counts = counts, assay = "RNA", meta.data = data.frame( batch = rep(c("one", "two"), each = 15), row.names = colnames(counts) ), project = "preserved-project" ) object[["ADT"]] <- SeuratObject::CreateAssay5Object( counts = counts[seq_len(5), , drop = FALSE] ) object[["existing_pca"]] <- SeuratObject::CreateDimReducObject( embeddings = matrix( rnorm(ncol(counts) * 2), nrow = ncol(counts), dimnames = list(colnames(counts), c("OLDPC_1", "OLDPC_2")) ), assay = "RNA", key = "OLDPC_" ) SeuratObject::Idents(object) <- factor( rep(c("A", "B"), each = 15) ) SeuratObject::Misc(object, slot = "owner") <- "unchanged" add_example_tool <- function(x) { SeuratObject::Tool(x) <- list(owner = "unchanged") x } object <- add_example_tool(object) existing_tool_names <- SeuratObject::Tool(object) ``` ## Run the workflow Input assay and layer names are exact. `assay = NULL` uses the default assay, while `layer = "counts"` is explicit by default. ```{r workflow} result <- cudacell_seurat( object, assay = "RNA", layer = "counts", n_hvg = 30, n_components = 5, k = 5, batch_size = 8, device = "cpu" ) SeuratObject::Assays(result) SeuratObject::Reductions(result) SeuratObject::Neighbors(result) ``` The default outputs use namespaced native locations: ```{r outputs} normalized <- SeuratObject::LayerData( result[["CUDACELL"]], layer = "data", fast = FALSE ) normalized[1:3, 1:3] SeuratObject::Embeddings(result[["cudacell_pca"]])[1:3, , drop = FALSE] SeuratObject::Indices(result[["cudacell_knn"]])[1:3, , drop = FALSE] result[["CUDACELL"]][[]][ 1:3, c( "cudacell_mean", "cudacell_variance", "cudacell_dispersion", "cudacell_hvg", "cudacell_hvg_rank" ) ] ``` `cudacell_hvg_rank` is the one-based global dispersion rank across every input feature. `cudacell_hvg` marks the selected top `n_hvg` features, which are also registered through `SeuratObject::VariableFeatures()`. The exact directed kNN result is stored as a `Neighbor`, including both integer indices and distances. The PCA `DimReduc` includes cell embeddings, feature loadings, standard deviations, and the `CUDACELLPC_` key. ## Verify preservation The input object is unchanged, and unrelated state survives in the result: ```{r preservation} identical( SeuratObject::LayerData(object[["RNA"]], "counts"), SeuratObject::LayerData(result[["RNA"]], "counts") ) identical(object[["ADT"]], result[["ADT"]]) identical(object[["existing_pca"]], result[["existing_pca"]]) identical(SeuratObject::Idents(object), SeuratObject::Idents(result)) identical( SeuratObject::Misc(object, slot = "owner"), SeuratObject::Misc(result, slot = "owner") ) all(vapply( existing_tool_names, function(name) { identical( SeuratObject::Tool(object, slot = name), SeuratObject::Tool(result, slot = name) ) }, logical(1) )) ``` cudacellr adds its own deterministic `cudacell_seurat` tool record without replacing existing tool records. ## Collision and realization safety Every target assay, reduction, neighbour, feature-metadata column, cell-metadata column, tool record, and Seurat key is checked before device selection, layer access, realization, or numerical work. A second run with the same names fails: ```{r collision, error=TRUE} cudacell_seurat( result, n_hvg = 30, n_components = 5, k = 5, device = "cpu" ) ``` Use `overwrite = TRUE` only when replacing those exact cudacellr outputs is intentional. Cross-type name or key collisions are never overwritten. Only ordinary in-memory `matrix` and `Matrix` layers are accepted by default. Delayed, on-disk, and other matrix-like layers are not silently collected. Set `realize = TRUE` only after confirming that the selected layer fits in memory; the original layer class and materialization decision are recorded. For `device = "cuda"`, CUDA availability is validated before the layer is read or realized. The request remains strict and never silently falls back to CPU. ## Provenance The native tool record contains identifiers, parameters, output locations, and the same ordered `cudaverse-stage/1` compute provenance used by the matrix and SingleCellExperiment workflows: ```{r provenance} cuda_provenance(result) SeuratObject::Tool(result, slot = "cudacell_seurat")$outputs SeuratObject::Tool(result, slot = "cudacell_seurat")$parameters ```