57 lines
3.2 KiB
Python
57 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Held-out whole-brain readout for independent Phase 4N control E overlays."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
from phase4h_audit import write_json
|
|
from phase4i import Validator
|
|
from phase4j import effect
|
|
from phase4l import OdorSimulator, pn_drive
|
|
from phase4m import load_odor_inputs
|
|
from phase4n import load_config
|
|
|
|
|
|
def main():
|
|
ap=argparse.ArgumentParser();ap.add_argument("--config",type=Path,required=True);args=ap.parse_args()
|
|
ncfg,mcfg,cfg,basepath=load_config(args.config);exp=Path(ncfg["experiment_root"])
|
|
identity=pd.read_parquet(exp/"edge-identity/frozen-edge-identity.parquet")
|
|
v=Validator(cfg,basepath,exp);sim=OdorSimulator(v,cfg,exp)
|
|
w=identity.anatomical_weight_mv.to_numpy(np.float32)
|
|
panel,vectors,selection,mapping=load_odor_inputs(cfg);gloms=selection["glomeruli_order"];ms=float(np.median(panel.mapped_response_sum))
|
|
pn={}
|
|
for odor in ("A","B"):
|
|
oid=selection[f"ODOR_{odor}"]["odor_id"]
|
|
pn[odor]=pn_drive(oid,vectors[oid],mapping,gloms,str(mcfg["protocol"]["input_mode"]),ms,cfg)[:2]
|
|
rows=[];walls=[];conditions=("B+matched-US","A+random-US-timing","A+unrelated-compartment-US")
|
|
for seed,es in zip(ncfg["train_seeds"],ncfg["evaluation_seeds"]):
|
|
baseline={odor:sim.run_rates(*pn[odor],es,float(mcfg["protocol"]["duration_ms"])) for odor in pn}
|
|
for pair in (50,100):
|
|
for condition in conditions:
|
|
with np.load(exp/"controls"/f"E-{condition}-seed-{seed}-pairings-{pair}.npz") as f:E=f["E"].copy()
|
|
delta=w*(E-1)
|
|
for odor in ("A","B"):
|
|
post=sim.run_rates(*pn[odor],es,float(mcfg["protocol"]["duration_ms"]),delta=delta)
|
|
e=effect(baseline[odor],post);walls.append(post["wall_seconds"])
|
|
rows.append({"condition":condition,"train_seed":seed,"eval_seed":es,"pairings":pair,"odor":odor,
|
|
"MBON_spike_L1":e["MBON_spike_l1"],"downstream_spike_L1":e["downstream_spike_l1"],
|
|
"KC_spike_L1":int(np.abs(post["kc_counts"]-baseline[odor]["kc_counts"]).sum()),
|
|
"finite":bool(post["finite"]),"wall_seconds":post["wall_seconds"]})
|
|
print(json.dumps({"seed":seed,"completed_control_wholebrain":True}),flush=True)
|
|
table=pd.DataFrame(rows);table.to_parquet(exp/"controls/wholebrain-heldout-control-replay.parquet",index=False)
|
|
pivot=table.pivot(index=["condition","pairings","train_seed"],columns="odor",values="MBON_spike_L1").reset_index()
|
|
pivot["A_minus_B"]=pivot["A"]-pivot["B"]
|
|
summary=pivot.groupby(["condition","pairings"]).agg(A_minus_B_mean=("A_minus_B","mean"),A_specific_seeds=("A_minus_B",lambda x:int((x>0).sum()))).reset_index()
|
|
write_json(exp/"controls/wholebrain-summary.json",{"rows":len(table),"conditions":summary.to_dict("records"),
|
|
"total_brain_wall_seconds":float(sum(walls)),"frozen_E1_reference_reused_per_evaluation_seed":True,
|
|
"A_D0_and_frozen_E1_effect_are_exactly_zero_by_E_identity":True})
|
|
print(json.dumps(summary.to_dict("records")),flush=True)
|
|
|
|
|
|
if __name__=="__main__":main()
|