trackcell ========= Full specification: ``docs/INTEGRATION.md`` in the repository. Scope ----- pyglmGamPoi implements the default SCT v2 offset model: * formula ``y ~ log_umi`` → intercept-only GLM with ``offset = log(10^log10_umi)`` * fixed slope ``log_umi = log(10)`` * output columns ``theta``, ``Intercept``, ``log_umi`` (genes × 3 DataFrame) Recommended patch in trackcell ``fit_offset_model``: .. code-block:: python from pyglmGamPoi import fit_offset_model, is_available if method == "glmGamPoi_offset" and is_available(): return fit_offset_model( umi, regressor_data, gene_index, allow_inf_theta=allow_inf_theta, apply_shrinkage=True, ) Matrix layout ------------- * **Input to pyglmGamPoi:** genes × cells (trackcell VST internal layout after transpose) * **AnnData default:** cells × genes — transpose before calling, or use ``pyglmGamPoi.adata`` ``allow_inf_theta`` ------------------- When ``True`` (trackcell SCT v2 default), genes at the Poisson boundary (overdispersion MLE ``= 0``) receive ``theta = Inf``, matching R ``fit_glmGamPoi_offset(..., allow_inf_theta = TRUE)``. When ``False``, ``theta`` is capped at ``mean(mu) / 1e-4`` per gene. Parity status ------------- .. list-table:: :header-rows: 1 :widths: 40 15 45 * - Feature - Status - Notes * - Per-gene intercept + offset NB - done - Newton + Brent; ``rough_beta_init`` fix for scRNA counts * - Cox-Reid overdispersion MLE - done - Local golden section + Newton; matches R ``nlminb`` * - Inf ``theta`` / ``allow_inf_theta`` - done - 217/217 on GSE288946 step1 vs R live * - Cross-gene ``overdispersion_shrinkage`` - done - ``loc_median_fit`` on first-pass ``rowMeans(Mu)`` + intercept refit * - ``fit_glmGamPoi_offset`` vs R golden - done - ``tests/test_parity_r.py``, ``tests/test_theta_od_parity.py`` Algorithm notes --------------- Overdispersion MLE uses the same Cox-Reid adjusted log-likelihood as ``glmGamPoi::overdispersion_mle_impl``. Optimization starts from the method-of-moments dispersion and searches locally (``log_start ± 8`` on ``log_theta``) to avoid numerical artefacts at ``log_theta < -30``. If the first OD pass at the initial intercept collapses to ~Poisson, OD is retried after refitting the intercept.