#!/usr/bin/env python3 """ Periodic Table Sweep — v6c Two-Curve Architecture ================================================================================ Run every element through the v6c cascade and measure: - At what fill level each element's pockets crystallize - The global_r, σ, frequency range at equilibrium - Whether heavier elements sit deeper on the C_potential curve - Element differentiation in the local structure The cipher predicts: lighter elements form at shallow well depth, heavier elements require deeper wells. The simulation should produce this progression WITHOUT element-specific parameters — only mass differs between elements. Run elements in parallel batches (4 at a time to use available cores). """ import json import sys import math import numpy as np import time as time_mod from datetime import datetime, timezone from pathlib import Path from concurrent.futures import ProcessPoolExecutor, as_completed sys.path.insert(0, str(Path(__file__).parent)) from importlib import import_module spec = import_module("SIM-003_v6c_wave_reinjection") CascadeEngine = spec.CascadeEngine ELEMENT_MASS_AMU = spec.ELEMENT_MASS_AMU RESULTS_DIR = Path(__file__).parent / "results_periodic_sweep" RESULTS_DIR.mkdir(exist_ok=True) def run_element(element, n_cycles=3000, N3=64): """Run one element through v6c and return summary results.""" try: engine = CascadeEngine(element, delta_r_base=0.0001, N1=2048, N2=256, N3=N3, max_dim=3) result = engine.run(n_cycles=n_cycles, verbose=False) # Extract key metrics p1 = result.get("phase1", {}) p2 = result.get("phase2", {}) p3 = result.get("phase3", {}) summary = { "element": element, "mass_amu": ELEMENT_MASS_AMU[element], "A_scale": result.get("A_scale", 0), "n_cycles": n_cycles, "elapsed_s": result.get("elapsed_s", 0), "1D": { "global_r": p1.get("global_r", 0), "fill": p1.get("global_fill", 0), "std_r": p1.get("std_r", 0), "is_eq": p1.get("is_equilibrium", False), }, "2D": { "global_r": p2.get("global_r", 0), "fill": p2.get("global_fill", 0), "std_r": p2.get("std_r", 0), "f_current_max": p2.get("f_current_max", 0), "is_eq": p2.get("is_equilibrium", False), "symmetry": p2.get("symmetry", {}).get("dominant_fold", 0), }, "3D": { "global_r": p3.get("global_r", 0), "fill": p3.get("global_fill", 0), "std_r": p3.get("std_r", 0), "min_r": p3.get("min_r", 0), "max_r": p3.get("max_r", 0), "f_current_max": p3.get("f_current_max", 0), "is_eq": p3.get("is_equilibrium", False), "beam_waist": p3.get("beam_waist_cells", 0), "overflow_local": p3.get("overflow_local_total", 0), "structure": p3.get("structure", {}).get("dominant_symmetry", "none"), "mid_cv": p3.get("structure", {}).get("mid_plane_cv", 0), }, "pulses_1to2": result.get("cascade", {}).get("pulse_counts", {}).get("1", 0), "pulses_2to3": result.get("cascade", {}).get("pulse_counts", {}).get("2", 0), } return summary except Exception as e: return {"element": element, "error": str(e)} def main(): import argparse parser = argparse.ArgumentParser(description="Periodic Table Sweep — v6c") parser.add_argument("--cycles", type=int, default=3000) parser.add_argument("--grid-3d", type=int, default=64, help="3D grid (64 for speed, 128 for detail)") parser.add_argument("--workers", type=int, default=4, help="Parallel workers") args = parser.parse_args() elements = list(ELEMENT_MASS_AMU.keys()) print("=" * 70) print("PERIODIC TABLE SWEEP — v6c TWO-CURVE ARCHITECTURE") print(f" {datetime.now(timezone.utc).isoformat()}") print(f" {len(elements)} elements, {args.cycles} cycles each") print(f" 3D grid: {args.grid_3d}³, {args.workers} parallel workers") print(f" Testing: do heavier elements sit deeper on the C_potential curve?") print("=" * 70) t_start = time_mod.monotonic() results = [] # Run in parallel batches with ProcessPoolExecutor(max_workers=args.workers) as executor: futures = { executor.submit(run_element, elem, args.cycles, args.grid_3d): elem for elem in elements } for future in as_completed(futures): elem = futures[future] try: result = future.result() results.append(result) if "error" in result: print(f" ERROR {elem}: {result['error']}") else: r3 = result["3D"] print(f" {elem:>3s} (A={result['A_scale']:>7.3f}): " f"3D gr={r3['global_r']:.4f} fill={r3['fill']:.3f} " f"σ={r3['std_r']:.4f} " f"sym={r3['structure']:>7s} " f"{'EQ' if r3['is_eq'] else ''}") except Exception as e: print(f" FAILED {elem}: {e}") results.append({"element": elem, "error": str(e)}) elapsed = time_mod.monotonic() - t_start # Sort by mass for the summary table results.sort(key=lambda r: r.get("mass_amu", 0)) print(f"\n{'='*70}") print("PERIODIC TABLE SUMMARY — sorted by mass") print(f"{'='*70}") print(f"{'Elem':>4s} {'Mass':>7s} {'A_scl':>6s} | " f"{'1D_eq':>5s} {'2D_gr':>6s} {'2D_eq':>5s} | " f"{'3D_gr':>6s} {'3D_fill':>7s} {'3D_σ':>6s} {'3D_eq':>5s} {'3D_sym':>7s} {'CV':>10s}") print("-" * 95) for r in results: if "error" in r: print(f"{r['element']:>4s} ERROR: {r['error'][:50]}") continue d1, d2, d3 = r["1D"], r["2D"], r["3D"] print(f"{r['element']:>4s} {r['mass_amu']:>7.2f} {r['A_scale']:>6.2f} | " f"{'Y' if d1['is_eq'] else 'N':>5s} {d2['global_r']:>6.4f} {'Y' if d2['is_eq'] else 'N':>5s} | " f"{d3['global_r']:>6.4f} {d3['fill']:>7.3f} {d3['std_r']:>6.4f} " f"{'Y' if d3['is_eq'] else 'N':>5s} {d3['structure']:>7s} {d3['mid_cv']:>10.2e}") # Key analysis: does 3D fill correlate with mass? valid = [r for r in results if "error" not in r] if len(valid) > 2: masses = np.array([r["mass_amu"] for r in valid]) fills_3d = np.array([r["3D"]["fill"] for r in valid]) sigmas_3d = np.array([r["3D"]["std_r"] for r in valid]) # Correlation if np.std(masses) > 0 and np.std(fills_3d) > 0: corr_fill = np.corrcoef(masses, fills_3d)[0, 1] corr_sigma = np.corrcoef(masses, sigmas_3d)[0, 1] print(f"\n Mass vs 3D fill correlation: r = {corr_fill:.4f}") print(f" Mass vs 3D σ correlation: r = {corr_sigma:.4f}") if corr_fill > 0.5: print(" >>> HEAVIER ELEMENTS FILL DEEPER — consistent with theory") elif corr_fill < -0.5: print(" >>> LIGHTER ELEMENTS FILL DEEPER — OPPOSITE of theory") else: print(" >>> No strong mass-fill correlation") print(f"\n Total elapsed: {elapsed:.0f}s ({elapsed/60:.1f} min)") # Save ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S") out = RESULTS_DIR / f"periodic_sweep_{ts}.json" output = { "timestamp": datetime.now(timezone.utc).isoformat(), "n_cycles": args.cycles, "grid_3d": args.grid_3d, "n_elements": len(elements), "workers": args.workers, "elapsed_s": elapsed, "results": results, } with open(out, "w") as f: json.dump(output, f, indent=2, default=float) print(f" Results: {out}") if __name__ == "__main__": main()