def save_survey(path, *, taxon_table, triangle, gene_labels, alignment_paths,
results, model_label, device, seed, n_iters,
description="", author=None) -> None:
"""Write a survey file: namespace, genes, anchor graph, one chart, the
per-gene archives (with elite newick trees), and provenance.
``results`` is one ``ArchiveResult`` per gene, aligned with ``gene_labels``.
"""
n_genes = len(gene_labels)
m = triangle.tree_metric
with h5py.File(path, "w") as f:
f.attrs["schema_version"] = _SCHEMA_VERSION
f.attrs["field_type"] = _FIELD_TYPE
f.attrs["metric"] = "normalized_branch_score"
f.attrs["seed"] = seed
f.attrs["n_genes"] = n_genes
f.attrs["n_charts"] = 1
f.attrs["created"] = datetime.datetime.now(datetime.timezone.utc).isoformat()
f.attrs["description"] = description
f.create_dataset("namespace/taxa",
data=np.array(taxon_table.labels, dtype=object),
dtype=_STR_DTYPE)
anchors = (triangle.r1, triangle.r2, triangle.r3)
for i, (label, apath) in enumerate(zip(gene_labels, alignment_paths)):
g = f.create_group(f"genes/{i}")
g.attrs["label"] = label
g.attrs["alignment_path"] = str(apath) if apath else ""
g.attrs["alignment_sha256"] = _sha256(apath) if apath else ""
g.create_dataset("nj_newick", data=anchors[i].as_newick(),
dtype=_STR_DTYPE)
ag = f.create_group("anchor_graph")
ag.attrs["anchor_gene_indices"] = np.arange(3, dtype=np.int32)
ag.create_dataset("dist", data=triangle.dist.astype(np.float64))
ag.create_dataset("qual", data=triangle.qual.astype(np.float64))
c = f.create_group("charts/0")
c.attrs["anchor_gene_indices"] = np.arange(3, dtype=np.int32)
c.attrs["metric_w"] = float(m.w)
c.attrs["c_ref"] = float(m.c_ref)
c.attrs["r_ref"] = float(m.r_ref)
c.attrs["cell"] = float(results[0].archive.cell)
c.attrs["origin"] = float(results[0].archive.origin)
from hifuku.anchor_triangle import triangle_quality
Q, _, _ = triangle_quality(triangle.P1, triangle.P2, triangle.P3)
c.attrs["Q"] = float(Q)
c.create_dataset("P", data=np.stack(
[triangle.P1, triangle.P2, triangle.P3]).astype(np.float64))
for k, res in enumerate(results):
arch = res.archive
gk = c.create_group(f"genes/{k}")
keys = list(arch.keys)
gk.attrs["gene_index"] = k
gk.attrs["n_filled"] = arch.n_filled
gk.attrs["best_logL"] = arch.best_logL()
gk.attrs["converged"] = int(res.converged)
gk.attrs["halt_iter"] = int(res.halt_iter)
gk.attrs["device"] = device
gk.attrs["model"] = model_label
gk.attrs["n_iters"] = int(n_iters)
gk.attrs["seed"] = int(seed)
niche = np.array(keys, dtype=np.int32).reshape(-1, 2)
logL = np.array([arch.elites[key].logL for key in keys], dtype=np.float64)
z = np.array([arch.elites[key].z for key in keys], dtype=np.float64)
newick = np.array([arch.tree_at(key).as_newick() for key in keys],
dtype=object)
gk.create_dataset("niche_ij", data=niche)
gk.create_dataset("logL", data=logL)
gk.create_dataset("z", data=z)
gk.create_dataset("tree", data=newick, dtype=_STR_DTYPE,
compression="gzip")
gk.create_dataset("history", data=res.history.astype(np.float64))
prov = f.create_group("provenance")
for key, val in _provenance(device, author).items():
prov.attrs[key] = val
rows = [[str(p) if p else "", _sha256(p) if p else ""]
for p in alignment_paths]
prov.create_dataset("inputs", data=np.array(rows, dtype=object),
dtype=_STR_DTYPE)