# Regenerate all isotope files (Known strict, Predicted-only, Master Known vs Predicted + Gap, JSON, Top-Gap)
import pandas as pd
import json
# --- 1) Strict Known Ledger (Z=1–118) ---
# Rows: Element label, Known, Stable (strict)
rows_known = [
("H (1)", 7, 2), ("He (2)", 9, 2), ("Li (3)", 11, 2), ("Be (4)", 12, 1), ("B (5)", 13, 2), ("C (6)", 15, 2),
("N (7)", 16, 2), ("O (8)", 17, 3), ("F (9)", 18, 1), ("Ne (10)", 19, 3), ("Na (11)", 20, 1), ("Mg (12)", 22, 3),
("Al (13)", 22, 1), ("Si (14)", 23, 3), ("P (15)", 23, 1), ("S (16)", 24, 4), ("Cl (17)", 24, 2), ("Ar (18)", 24, 3),
("K (19)", 24, 2), ("Ca (20)", 24, 6), ("Sc (21)", 25, 1), ("Ti (22)", 26, 5), ("V (23)", 26, 1), ("Cr (24)", 26, 4),
("Mn (25)", 26, 1), ("Fe (26)", 28, 4), ("Co (27)", 29, 1), ("Ni (28)", 31, 5), ("Cu (29)", 29, 2), ("Zn (30)", 30, 5),
("Ga (31)", 31, 2), ("Ge (32)", 32, 5), ("As (33)", 33, 1), ("Se (34)", 30, 6), ("Br (35)", 31, 2), ("Kr (36)", 32, 6),
("Rb (37)", 32, 1), ("Sr (38)", 34, 4), ("Y (39)", 32, 1), ("Zr (40)", 34, 5), ("Nb (41)", 34, 1), ("Mo (42)", 35, 7),
("Tc (43)", 36, 0), ("Ru (44)", 37, 7), ("Rh (45)", 35, 1), ("Pd (46)", 36, 6), ("Ag (47)", 38, 2), ("Cd (48)", 39, 8),
("In (49)", 39, 2), ("Sn (50)", 40, 10), ("Sb (51)", 36, 2), ("Te (52)", 38, 8), ("I (53)", 37, 1), ("Xe (54)", 40, 9),
("Cs (55)", 39, 1), ("Ba (56)", 40, 7), ("La (57)", 39, 1), ("Ce (58)", 40, 4), ("Pr (59)", 39, 1), ("Nd (60)", 41, 5),
("Pm (61)", 39, 0), ("Sm (62)", 41, 7), ("Eu (63)", 40, 2), ("Gd (64)", 41, 7), ("Tb (65)", 39, 1), ("Dy (66)", 40, 7),
("Ho (67)", 39, 1), ("Er (68)", 40, 6), ("Tm (69)", 39, 1), ("Yb (70)", 41, 7), ("Lu (71)", 40, 1), ("Hf (72)", 36, 5),
("Ta (73)", 37, 1), ("W (74)", 35, 5), ("Re (75)", 39, 1), ("Os (76)", 35, 7), ("Ir (77)", 34, 2), ("Pt (78)", 35, 6),
("Au (79)", 36, 1), ("Hg (80)", 38, 7), ("Tl (81)", 39, 2), ("Pb (82)", 43, 4), ("Bi (83)", 41, 0), ("Po (84)", 42, 0),
("At (85)", 39, 0), ("Rn (86)", 39, 0), ("Fr (87)", 34, 0), ("Ra (88)", 34, 0), ("Ac (89)", 33, 0), ("Th (90)", 31, 1),
("Pa (91)", 29, 0), ("U (92)", 28, 0), ("Np (93)", 20, 0), ("Pu (94)", 20, 0), ("Am (95)", 17, 0), ("Cm (96)", 19, 0),
("Bk (97)", 21, 0), ("Cf (98)", 20, 0), ("Es (99)", 18, 0), ("Fm (100)", 19, 0), ("Md (101)", 16, 0), ("No (102)", 13, 0),
("Lr (103)", 16, 0), ("Rf (104)", 18, 0), ("Db (105)", 16, 0), ("Sg (106)", 14, 0), ("Bh (107)", 15, 0), ("Hs (108)", 15, 0),
("Mt (109)", 13, 0), ("Ds (110)", 15, 0), ("Rg (111)", 11, 0), ("Cn (112)", 9, 0), ("Nh (113)", 9, 0), ("Fl (114)", 6, 0),
("Mc (115)", 4, 0), ("Lv (116)", 4, 0), ("Ts (117)", 2, 0), ("Og (118)", 1, 0)
]
known = pd.DataFrame(rows_known, columns=["Element (Z)", "Known", "Stable"])
known["Unstable"] = known["Known"] - known["Stable"]
# Save known strict
known_csv = "/mnt/data/isotope_master_summary_Z1-118_strict.csv"
known_md = "/mnt/data/isotope_master_summary_Z1-118_strict.md"
known.to_csv(known_csv, index=False)
with open(known_md, "w", encoding="utf-8") as f:
f.write(known.to_markdown(index=False))
# --- 2) Predicted-only Ledger (scaled to total 7,759) ---
KNOWN_TOTAL = known["Known"].sum() # 3269
TARGET_TOTAL = 7759
scale = TARGET_TOTAL / KNOWN_TOTAL # ≈ 2.3735
pred = known[["Element (Z)", "Known"]].copy()
pred["Predicted Isotopes (est.)"] = (pred["Known"] * scale).round().astype(int)
# Correct rounding drift to hit 7,759 exactly
drift = TARGET_TOTAL - pred["Predicted Isotopes (est.)"].sum()
if drift != 0:
frac = (pred["Known"] * scale) - pred["Predicted Isotopes (est.)"]
idx = frac.idxmax() if drift > 0 else frac.idxmin()
pred.loc[idx, "Predicted Isotopes (est.)"] += drift
pred_csv = "/mnt/data/isotope_predicted_only_Z1-118.csv"
pred_md = "/mnt/data/isotope_predicted_only_Z1-118.md"
pred.to_csv(pred_csv, index=False)
with open(pred_md, "w", encoding="utf-8") as f:
f.write(pred.to_markdown(index=False))
# --- 3) Master (Known vs Predicted + Gap) ---
master = pd.merge(known, pred[["Element (Z)", "Predicted Isotopes (est.)"]], on="Element (Z)", how="left")
master["Gap (Predicted - Known)"] = master["Predicted Isotopes (est.)"] - master["Known"]
master_csv = "/mnt/data/isotope_master_table_known_vs_predicted_with_gap.csv"
master_md = "/mnt/data/isotope_master_table_known_vs_predicted_with_gap.md"
master.to_csv(master_csv, index=False)
with open(master_md, "w", encoding="utf-8") as f:
f.write(master.to_markdown(index=False))
# --- 4) JSON for integration (SolveForce) ---
def parse_symbol(s): return s.split(" ")[0]
def parse_z(s): return int(s.split("(")[1].split(")")[0])
master["element_symbol"] = master["Element (Z)"].apply(parse_symbol)
master["element_z"] = master["Element (Z)"].apply(parse_z)
json_out = master[["element_z","element_symbol","Known","Stable","Unstable","Predicted Isotopes (est.)","Gap (Predicted - Known)"]]\
.rename(columns={"Predicted Isotopes (est.)":"Predicted","Gap (Predicted - Known)":"Gap"})\
.sort_values("element_z")
json_path = "/mnt/data/isotopes_master.json"
with open(json_path, "w", encoding="utf-8") as f:
json.dump(json_out.to_dict(orient="records"), f, ensure_ascii=False, indent=2)
# --- 5) Top 25 Gap report (CSV + MD) ---
top_gap = json_out.sort_values("Gap", ascending=False).head(25)
top_gap_csv = "/mnt/data/isotopes_top_gap_25.csv"
top_gap_md = "/mnt/data/isotopes_top_gap_25.md"
top_gap.to_csv(top_gap_csv, index=False)
with open(top_gap_md, "w", encoding="utf-8") as f:
f.write(top_gap.to_markdown(index=False))
# Show brief previews
from caas_jupyter_tools import display_dataframe_to_user
display_dataframe_to_user("Preview — Master Known vs Predicted + Gap", master.head(20))
display_dataframe_to_user("Top 25 Gap Elements", top_gap)
# Return paths
{
"known_csv": known_csv, "known_md": known_md,
"pred_csv": pred_csv, "pred_md": pred_md,
"master_csv": master_csv, "master_md": master_md,
"json_path": json_path, "top_gap_csv": top_gap_csv, "top_gap_md": top_gap_md,
"scale_factor": scale, "pred_total": int(pred['Predicted Isotopes (est.)'].sum())
}