# Lysogenization Frequency Calculator — Design & Handoff Specification

*Seed document for a new project/chat. Everything below is what is needed to
recapitulate the analysis of Geng et al. (2024) lysogenization data developed in
a prior chat, and to turn it into a calculator others can use. Companion to the
existing Poisson calculator (Poisson.phage.org); this is its lysogenization-
frequency extension.*

---

## 1. Purpose

A web tool ("Lysogenization Frequency Calculator") that:

1. Plots an observed **lysogenization frequency vs. multiplicity of infection
   (MOI)** curve.
2. Overlays the two **Poisson adsorption reference curves** (every infection
   lysogenizes; every multiple adsorption lysogenizes) and a fitted/assumed
   **single- vs. multiple-infection decomposition model**.
3. Lets a user either load their own (MOI, frequency, error) data or use the
   built-in **example curve = Geng et al. (2024), Fig. 4c**.
4. Surfaces the two things that make these numbers hard to interpret:
   **completeness of adsorption** (accuracy of reported MOIs) and the
   **near-resolution-limit behavior at low MOI**.

The intended user is someone measuring lysogenization frequency across MOI who
wants to know whether *single-phage* infection contributes to lysogeny, and how
much of any apparent single-phage signal is real vs. an adsorption/inference
artifact. (Few will run such experiments, but the tool is for those who do — and
for reading the existing literature correctly.)

---

## 2. The core model (equations)

### 2.1 Single-cell MOI is Poisson-distributed

The **single-cell MOI**, *n*, is the number of phages that actually infect one
individual cell. Across a population it is Poisson-distributed with mean **λ**:

```
P(n; λ) = λ^n · e^(−λ) / n!
```

**Crucial distinction:** the reported experimental MOI is a *nominal* value
**M = (phages added) / (cells present)**. The Poisson mean that governs infection
is **not** M but

```
λ = a · M
```

where **a** is an **adsorption-efficiency / measurement factor (0 < a ≤ 1)** that
corrects for incomplete adsorption and for inaccuracy in measuring phage and cell
concentrations. Using M in place of λ overstates the true mean multiplicity and
misplaces every Poisson quantity below. **The x-axis of the example graph is the
adsorption-corrected λ = aM, not nominal M.** (See §6.)

P(n) is *exactly* the Poisson prediction — no biology is in it. All of the biology
lives in the lysogenization probabilities Q_n (below).

### 2.2 Reference curves (the Poisson "bounds")

Fraction of cells with **at least one** phage ("every infection lysogenizes"):

```
P(n≥1) = 1 − e^(−λ)                       # slope 1 on log-log at low λ  (∝ λ)
```

Fraction of cells with **two or more** phages ("every multiple adsorption
lysogenizes"):

```
P(n≥2) = 1 − e^(−λ) − λ·e^(−λ)            # slope 2 on log-log at low λ  (∝ λ²)
```

Exactly-one:

```
P(1) = λ · e^(−λ)                          # slope 1 at low λ  (∝ λ)
```

The **slope difference (1 vs. 2)** at low MOI is the entire diagnostic: a
single-phage contribution rides on the λ¹ term and therefore *diverges upward*
from the λ² multiple-adsorption curve as MOI drops.

Handy low-MOI rule of thumb: among *infected* cells, the fraction that are
multiply infected ≈ **λ/2**. (At λ = 0.01, ~0.5% of infecteds are multiples,
so single : multiple ≈ 200 : 1 by *population*; at λ = 0.001, ~2000 : 1.)

### 2.3 The lysogenization model (single- vs. multiple-infection)

Let **Q_n** = probability that a cell infected by exactly *n* phages lysogenizes.
Observed per-total-cell lysogenization frequency:

```
f(λ) = Σ_{n≥1} P(n; λ) · Q_n
```

**Reduced two-parameter form** (used to generate the example graph), valid because
Q_n empirically saturates at n = 2 (see §3.2):

```
f(λ) = P(1)·q₁ + P(n≥2)·q₂
     = λ·e^(−λ)·q₁  +  [1 − e^(−λ) − λ·e^(−λ)]·q₂
```

- **q₁** = fraction of *singly* infected cells that lysogenize.
- **q₂** = fraction of *multiply* adsorbed cells that lysogenize (n = 2 value,
  assumed to hold for all n ≥ 2).

Example-curve values (round approximations of Geng's fit): **q₁ = 0.01,
q₂ = 0.50**.

**Multiples-only reference** (the curve the data should *diverge from* if singles
contribute):

```
f_mult(λ) = P(n≥2)·q₂
```

Ratio (full model) / (multiples only) grows as MOI falls — this is the single-
phage signal made quantitative:

| λ (MOI) | f(λ) model | f_mult only | ratio |
|--------:|-----------:|------------:|------:|
| 0.001   | 1.0e−5     | 2.5e−7      | 41    |
| 0.003   | 3.2e−5     | 2.3e−6      | 14    |
| 0.01    | 1.2e−4     | 2.5e−5      | 5.0   |
| 0.03    | 5.1e−4     | 2.2e−4      | 2.3   |
| 0.1     | 3.2e−3     | 2.3e−3      | 1.4   |
| 0.3     | 2.1e−2     | 1.9e−2      | 1.1   |
| 1       | 1.4e−1     | 1.3e−1      | 1.0   |
| 3       | 4.0e−1     | 4.0e−1      | 1.0   |

### 2.4 Relationship to Geng et al.'s published model

Geng et al. fit the **general** form f(λ) = Σ_n P(n)·Q_n, allowing a non-zero Q_n
at **every** n (following an approach that does *not* assume a hard two-phage
threshold). Their fitted Q_n was found to **saturate at n = 2**:

- **Q₁ ≈ 0.005 – 0.009** (single-phage lysogenization; the two runs)
- **Q₂ = Q₃ = Q₄ ≈ 0.41 – 0.47**

So the reduced two-parameter model in §2.3 is *their result*, not a competing one:
fixing q₂ as a single saturated value and keeping only q₁ for single infections
reproduces their fit in the relevant regime (where n ≥ 3 cells are negligibly
rare). The round numbers (q₁ = 1%, q₂ = 50%) are the approximations. The tool
should therefore let the user set q₁ and q₂ directly (assume-and-check) **and/or**
fit them to the data (as Geng did).

---

## 3. Example dataset: Geng et al. (2024), Fig. 4c

**Source:** Geng, Y. et al. "Using bacterial population dynamics to count phages
and their lysogens." *Nature Communications* (2024). Data from the paper's
**Source Data** file, sheet **Fig4c** (publicly available with the article). Two
independent runs. Host: log-phase *E. coli* MG1655. Phage: λ (λts, cI857
bor::kanR); lysogens scored by kanamycin resistance via OD growth dynamics.

Columns: **average (adsorption-corrected) MOI = λ = aM**, **frequency of lysogeny
(per total cell)**, **error**.

### Run 1
```
MOI(λ)        freq          error
6.6818566     0.3855933     0.0138974
3.3409283     0.4364224     0.1130184
1.6704641     0.2362619     0.0175319
0.8352321     0.1474681     0.0209011
0.4176160     0.0329160     0.0009088
0.2088080     0.0101849     0.0010854
0.1044040     0.0020593     0.0003823
0.0522020     0.0008073     0.0000609
0.0261010     0.0002877     0.0000601
0.0130505     0.0001155     0.0000414
0.0065253     0.0000660     0.0000169
0.0032626     0.0000555     0.0000186
0.0016313     0.0000129     0.0000065
0.0008157     0.0000023     0.0000023
```

### Run 2
```
MOI(λ)        freq          error
3.6659998     0.3373758     0.0308942
1.8329999     0.2364629     0.0326061
0.9165000     0.1096486     0.0215528
0.4582500     0.0402457     0.0059593
0.2291250     0.0153841     0.0076008
0.1145625     0.0021251     0.0003016
0.0572812     0.0012190     0.0000508
0.0286406     0.0004266     0.0000809
0.0143203     0.0000812     0.0000297
0.0071602     0.0000455     0.0000202
0.0035801     0.0000079     0.0000045
0.0017900     0.0000051     0.0000051
0.0008950     0.0000168     0.0000106
```

Notes:
- These MOIs are the **corrected** values (they match the "corrected for adsorption
  efficiency" column of the paper's Fig. 4b, extended to lower MOI). Plotting the
  Poisson references directly at these λ is therefore apples-to-apples.
- The **lowest 1–2 points of each run** sit near the assay resolution limit and are
  noisy (e.g., the Run 2 point at MOI 0.000895, freq 1.68e−5 ± 1.06e−5). Do **not**
  let a single extreme low-MOI point drive interpretation (see §6). The example
  plot should show them but the single-phage claim rests on the *trend*, not any
  one point.

---

## 4. Graph specification

Reproduces the figure developed in the prior chat.

- **Axes:** both **log scale**.
  - x: `average (adsorption-corrected) MOI, λ`; range ≈ **6e−4 to 9**.
  - y: `frequency of lysogeny (per total cell)`; range ≈ **1e−6 to 1.3**.
- **Curves** (evaluate over λ ∈ logspace(6e−4, 9), ~500 pts):
  1. **P(n≥1)** = 1 − e^(−λ) — *dotted gray*, label "every infection lysogenizes
     [P(n≥1)]". Upper bound.
  2. **P(n≥2)** = 1 − e^(−λ) − λe^(−λ) — *dash-dot gray*, label "every multiple
     lysogenizes [P(n≥2)]".
  3. **multiples only** = P(n≥2)·q₂ — *dashed dark gray*, label "multiples only:
     50% of n≥2".
  4. **full model** = P(1)·q₁ + P(n≥2)·q₂ — *solid, colored, thickest*, label
     "+ single-phage: 1% of n=1".
- **Data:** two series with error bars.
  - Run 1: open **circles**.
  - Run 2: open **squares**.
  - (Run colors are *run identity*, not lysis/lysogeny; blue/orange were used and
    are fine. NB: the project's lysis/lysogeny color convention — green = lysis,
    red = lysogeny — applies to *schematics*, not to this data plot's run markers.)
- **Legend:** lower-right.
- **Key visual message:** at low MOI the data leaves the dashed "multiples only"
  curve and tracks the solid full-model curve up toward the P(n≥1) slope; data
  rising **above** the P(n≥2) "every multiple" bound is direct evidence of a
  single-phage contribution (you cannot exceed 100% of multiples unless singles
  also lysogenize).

### 4.1 Reference implementation (matplotlib — generates the exact example)

```python
import numpy as np, matplotlib.pyplot as plt

def poisson_terms(lam):
    P1   = lam*np.exp(-lam)
    Pge1 = 1 - np.exp(-lam)
    Pge2 = 1 - np.exp(-lam) - lam*np.exp(-lam)
    return P1, Pge1, Pge2

def model(lam, q1=0.01, q2=0.50):
    P1,_,Pge2 = poisson_terms(lam)
    return P1*q1 + Pge2*q2            # full: singles + multiples

def multiples_only(lam, q2=0.50):
    _,_,Pge2 = poisson_terms(lam)
    return Pge2*q2

# --- data (Geng 2024 Fig4c): arrays m1,f1,e1 (run1) and m2,f2,e2 (run2) ---
lam = np.logspace(np.log10(6e-4), np.log10(9), 500)
P1, Pge1, Pge2 = poisson_terms(lam)
q1, q2 = 0.01, 0.50

fig, ax = plt.subplots(figsize=(6.6,5.4))
ax.plot(lam, Pge1, ':',  color='#888', lw=1.4, label='every infection lysogenizes [P(n≥1)]')
ax.plot(lam, Pge2, '-.', color='#888', lw=1.4, label='every multiple lysogenizes [P(n≥2)]')
ax.plot(lam, Pge2*q2,      '--', color='#555', lw=1.7, label='multiples only: 50% of n≥2')
ax.plot(lam, P1*q1+Pge2*q2,'-',  color='#B0333B', lw=2.1, label='+ single-phage: 1% of n=1')
ax.errorbar(m1,f1,yerr=e1, fmt='o', ms=5,   mfc='white', mew=1.2, capsize=2, lw=1, label='observed (run 1)')
ax.errorbar(m2,f2,yerr=e2, fmt='s', ms=4.5, mfc='white', mew=1.2, capsize=2, lw=1, label='observed (run 2)')
ax.set_xscale('log'); ax.set_yscale('log')
ax.set_xlim(6e-4, 9); ax.set_ylim(1e-6, 1.3)
ax.set_xlabel('average (adsorption-corrected) MOI, λ')
ax.set_ylabel('frequency of lysogeny (per total cell)')
ax.legend(fontsize=7.6, loc='lower right'); ax.grid(True, which='both', alpha=0.15)
```

For a web calculator, port the four curve functions and the log-log plotting to
JS (e.g., Plotly/D3); the math is elementary once `poisson_terms`, `model`, and
`multiples_only` are in place.

---

## 5. Completeness of adsorption & MOI accuracy (caveats the tool MUST surface)

These are the reasons a reported lysogenization-vs-MOI curve can mislead. The
calculator should let users toggle/inspect them.

### 5.1 Nominal vs. effective MOI (the `a` factor)
Reported MOI is **M = phages added / cells**. The Poisson mean that matters is
**λ = aM**, a < 1, absorbing incomplete adsorption and concentration-measurement
error. Consequences:
- If a curve is plotted vs. **nominal M** while the references are computed at M
  (i.e., assuming a = 1), the Poisson floor is **overstated** and the single-phage
  signal is **understated**. Correcting (a < 1) lowers λ, lowers the floor, and
  makes the low-MOI data sit **further above** the floor — i.e., the adsorption
  correction *helps* the single-phage reading.
- Geng fit `a` and validated it: best-fit `a` vs. bacterial density agreed with
  the *theoretically predicted adsorption efficiency*. A calculator should let the
  user enter an `a` (or an adsorption rate constant + density + time) to convert
  nominal M → λ, and should default the example to the already-corrected λ.

### 5.2 The missing MOI = 0 control (the key gap)
To claim single-phage lysogenization from the lowest-MOI points, one must exclude
a **phage-independent background** of the resistance marker: spontaneous marker
mutations, pre-existing resistant cells, incomplete selection, carryover. The
**only** clean discriminator is an **MOI = 0 well carried through the same
selection**, which measures that background directly. In Geng, a no-phage control
exists for lysis dynamics and a no-selection control exists for the denominator,
but a **MOI = 0 + selection** control (the one that bounds background lysogen
signal) is not reported. The tool should:
- Provide an optional **background-floor parameter `b`** (constant, MOI-independent
  added to f), and show how a nonzero `b` can absorb the low-MOI lift and drive the
  fitted q₁ toward zero. This is the honest sensitivity test: *is the single-phage
  signal robust to a plausible background?*
- Warn when the lowest data points are within a few-fold of `b` (or of the
  resolution floor) that they cannot, by themselves, establish single-phage
  lysogenization.

### 5.3 Assay type: OD-inference vs. plating
Geng did **not** plate/count colonies; lysogens were inferred from the **kinetics
of a kanamycin-selective culture** (extrapolating the selective growth curve back
to the dilution time). Implications:
- No small-integer Poisson **counting** noise (so scatter at low MOI is not
  count-limited); but
- **Back-extrapolation** across a huge dynamic range at tiny lysogen fractions is
  an **inference-level** uncertainty, fractionally largest where the signal is
  smallest (low MOI), and plausibly biased **upward** if the assumed lysogen
  growth/lag differs from the fit. This is the residual candidate for a systematic,
  one-directional, low-MOI deviation. The robust inference therefore comes from the
  **global fit constrained by well-measured mid-range points**, not the noisy
  low-MOI tail.

### 5.4 Artifacts that are (mostly) designed-out — document, don't over-worry
- **Premature lysis before selection:** in Geng, a 250× dilution at ~15 min post-
  infection precedes the first burst (~50–60 min latent period at 30 °C), so the
  first lytic cohort has not yet burst when adsorption is quenched.
- **Secondary (re)infection:** low cell density at infection (~10⁶–10⁷/mL) makes
  the second-order adsorption rate slow, and the 250× dilution drops both cell and
  phage density (rate ∝ [cells]·[phage] falls ~10⁴×). So progeny reinfection is
  negligible and cannot generate the low-MOI lift.
- These belong in the tool's documentation as "why the low-MOI deviation is likely
  *inference*, not *biology*," which narrows the interpretation to: genuine
  single-phage signal **or** background/back-extrapolation floor — discriminated
  only by the MOI = 0 control (§5.2).

---

## 6. Interpretation guide (what the curves mean)

- **Data on the multiples-only (dashed) curve, everywhere:** consistent with *no*
  single-phage lysogenization (all lysogeny from n ≥ 2). This is roughly the
  classic **Kourilsky (1973)** picture — log-phase lysogeny at/below the multiple-
  adsorption floor.
- **Data diverging upward from multiples-only toward P(n≥1) at low MOI:** a
  **non-zero single-phage** term (q₁ > 0). This is the **Geng (2024)** result, and
  it is consistent with the single-phage inference from **Kobiler et al. (2002)**
  (whose MOI 0.01 sits right at the *edge* of the deviation range).
- **Data above the P(n≥2) "every multiple" bound:** cannot be explained by
  multiples at any efficiency — direct evidence of single-phage lysogenization.
- **Magnitude:** for **log-phase** λ, single-phage lysogenization "tops out" around
  **~1% or less** (Geng q₁ ≈ 0.5–0.9%). In **stationary phase** the single-phage
  frequency is far higher (Kobiler ≈ 41%); i.e., single-phage lysogenization is a
  strong function of host growth state (decreasing ~exponentially with growth
  rate). The calculator's example is the *log-phase* regime.
- **Framing to avoid over-claiming:** three studies (Kourilsky, Kobiler, Geng) are
  *consistent* with a low, non-zero single-phage log-phase frequency; Kourilsky
  could only *bound* it (data at the floor), while Kobiler and Geng *resolve* it —
  but in each case near the limit of the assay, and (Geng, Kobiler) without an
  MOI = 0 background control. State the single-phage number as a **consistent
  upper-range estimate (~1%)**, not a firmly established value.

---

## 7. Suggested calculator features

1. **Inputs:** user pastes (MOI, frequency, [error]) rows, or picks "Geng 2024
   example." Toggle: are the MOIs *nominal M* or *corrected λ*? If nominal, ask for
   `a` (or adsorption params) to convert.
2. **Model controls:** sliders/fields for **q₁** (single-phage lysogenization
   fraction) and **q₂** (multiple-infection fraction); button to **fit** q₁, q₂
   (and optionally `a`, `b`) to the data. Default q₁ = 0.01, q₂ = 0.50.
3. **Background control:** optional constant **b** (MOI = 0 background). Show fitted
   q₁ with and without allowing b > 0 (the robustness test).
4. **Plot:** log-log; the four curves (§4) + data with error bars; highlight where
   the data crosses above P(n≥2).
5. **Readouts:** single vs. multiple **lysogen-contribution ratio** vs. MOI (from
   §2.3 table logic: ratio ∝ (2q₁)/(q₂·λ) at low λ); the crossover MOI where
   singles stop dominating; obs/floor ratios per point.
6. **Guidance panel:** the §5 caveats (adsorption completeness, MOI = 0 control,
   OD-inference vs. plating), shown contextually — e.g., flag points within a
   few-fold of the resolution floor or of `b`.
7. **Link** to the Poisson calculator (Poisson.phage.org) for the underlying
   e^(−MOI) survival/zero-class math.

---

## 8. References & connections

- **Geng et al. (2024)**, *Nat. Commun.*, "Using bacterial population dynamics to
  count phages and their lysogens." — example data (Fig. 4c Source Data); general
  Q_n model; adsorption factor `a`; single-cell MOI = Poisson(aM). Code/data repo:
  github.com/gengyuncong/PhageCounting.
- **Kobiler et al. (2002)**, *PNAS* 99:14964. — single-phage lysogenization in
  stationary vs. log phase; Poisson-floor argument at MOI 0.01.
- **Kourilsky (1973)**. — classic log-phase lysogeny vs. multiple-adsorption
  frequency; data at/below the P(n≥2) floor.
- **Kobiler et al. (2005)**, *PNAS* 102:4470. — CII threshold ≥2 by direct
  measurement; "single-phage lysogeny... may reflect unique cell physiology at the
  time of infection or a stochastic process."
- Companion tool: **Poisson calculator**, Poisson.phage.org.

---

## 9. One-paragraph summary for the new chat

Build a log-log calculator that plots lysogenization frequency vs. adsorption-
corrected MOI (λ = aM). Overlay P(n≥1) = 1−e^(−λ) and P(n≥2) = 1−e^(−λ)−λe^(−λ)
(the "every infection" and "every multiple adsorption" bounds), a multiples-only
curve P(n≥2)·q₂, and a full model f(λ) = P(1)·q₁ + P(n≥2)·q₂ where q₁ and q₂ are
the single- and multiple-infection lysogenization fractions (default 0.01 and
0.50, the round form of Geng et al. 2024's fitted Q₁ ≈ 0.005–0.009,
Q₂ ≈ 0.41–0.47, which saturate at n = 2). Use Geng's Fig. 4c (two runs, tabulated
in §3) as the example curve. The single-phage signal is the divergence of the full
model above the multiples-only curve as MOI falls (single term ∝ λ, multiple term
∝ λ²); data above the P(n≥2) bound is direct evidence of single-phage
lysogenization. Foreground the caveats: reported MOI must be corrected by
adsorption efficiency `a`; the lowest-MOI points sit near the assay's resolution
limit; and without an MOI = 0 + selection control the low-MOI lift cannot be
cleanly separated from a phage-independent background `b` — so report the
single-phage frequency (~1% for log-phase λ) as a consistent upper-range estimate,
not an established value.
