# Constructed viability data: compounds A and B, each tested in the same 4 independent experiments (one plate per
# experiment, both compounds on it), 9 concentrations (1 nM to 10 µM in half-log steps), triplicate wells.
# True IC50: A 100 nM, B 250 nM (2.5-fold); experiment-to-experiment shift in log10 IC50 (SD 0.15) shared by both
# compounds on a plate; well noise 5 percentage points.
import numpy as np, pandas as pd
rng = np.random.default_rng(2026)
conc = 10.0 ** np.arange(-9, -4.9, 0.5)        # mol/L: 1e-9 ... 1e-5 (9 concentrations)
def four_pl(x, bottom, top, log_ic50, hill):
    return bottom + (top - bottom) / (1 + 10 ** ((np.log10(x) - log_ic50) * hill))
rows = []
for e in range(1, 5):
    plate_shift = rng.normal(0, 0.15)
    for comp, log_ic50 in [("A", -7.0), ("B", np.log10(2.5e-7))]:
        li = log_ic50 + plate_shift + rng.normal(0, 0.08)
        for x in conc:
            for w in range(3):
                y = four_pl(x, 2, 100, li, 1.0) + rng.normal(0, 5)
                rows.append({"experiment": e, "compound": comp, "conc_M": x, "well": w + 1, "viability": round(y, 1)})
pd.DataFrame(rows).to_csv("viability.csv", index=False)
