Files
resonance-engine/scripts/comprehensive_analysis.py
T
Scruff AI 9302a86ea8 2026-03-28: EM spectrum overlay, CTO report, sweep/analysis scripts, prime analysis
New docs:
- docs/em_spectrum_overlay.html: Full EM spectrum with Khra/Gixx lines, physics markers, cell-size slider
- docs/2026-03-28_170500_cto-report_fractal-echo-analysis.txt: CTO fractal echo analysis report

New scripts (Beast sweep infrastructure + analyzers):
- scripts/nuclear_magic_analyzer.py: shell structure, peak clustering, mode counting, GUE tests
- scripts/physics_domain_analysis.py: 4-domain physics (nuclear shells, Brillouin, band gaps, GUE)
- scripts/direct_zmq_sweep.py: ZMQ direct sweep driver
- scripts/sweep_real.py: real sweep execution
- scripts/analyze_sweep.py, comprehensive_analysis.py: sweep analysis tools
- scripts/execute_prime_mapping.py: prime lattice mapping
- scripts/extrapolate_findings.py, check_extrapolation.py: extrapolation tools
- scripts/eta_calc.py, time_estimate.py, updated_estimate.py, show_pattern.py: utilities

Prime analysis (root):
- navigator_prime_analysis.py, navigator_prime_analysis_v2.py

Updated:
- navigator/mock_lbm_daemon.py, navigator/telemetry_server.py
2026-03-28 17:31:52 +07:00

860 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Comprehensive Data Analysis & Report Generator
Analyzes the 375-point EM parameter sweep and produces:
1. Full statistical summary (text)
2. Interactive HTML visualization dashboard
"""
import os
import sys
import numpy as np
import pandas as pd
from datetime import datetime
from collections import Counter
import json
# ── Config ──────────────────────────────────────────────────────────
MAGIC_NUMBERS = [2, 8, 20, 28, 50, 82, 126]
SWEEP_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "sweep_results")
RESULTS_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "results")
os.makedirs(RESULTS_DIR, exist_ok=True)
def load_data(csv_path=None):
if csv_path is None:
csvs = sorted([f for f in os.listdir(SWEEP_DIR) if f.startswith("em_direct_sweep") and f.endswith(".csv")])
if not csvs:
print("No sweep CSVs found"); sys.exit(1)
csv_path = os.path.join(SWEEP_DIR, csvs[-1])
print(f"Auto-selected: {csvs[-1]}")
df = pd.read_csv(csv_path)
print(f"Loaded {len(df)} points")
return df, os.path.basename(csv_path)
# ═══════════════════════════════════════════════════════════════════
# PART 1: Comprehensive Text Report
# ═══════════════════════════════════════════════════════════════════
def generate_text_report(df, source_name):
R = []
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
R.append("=" * 78)
R.append(" COMPREHENSIVE PARAMETER SWEEP ANALYSIS — RESONANCE ENGINE")
R.append("=" * 78)
R.append(f"Source: {source_name}")
R.append(f"Generated: {ts}")
R.append(f"Points: {len(df)}")
R.append(f"Duration: {df['timestamp'].iloc[0]}{df['timestamp'].iloc[-1]}")
R.append("")
# ── Section 1: Global Statistics ──
R.append("" * 78)
R.append("1. GLOBAL STATISTICS")
R.append("" * 78)
numeric_cols = ['omega', 'khra_amp', 'gixx_amp', 'coherence', 'asymmetry',
'vorticity_mean', 'gpu_temp_c', 'gpu_power_w', 'cycle']
R.append(f" {'Column':<18} {'Min':>12} {'Max':>12} {'Mean':>12} {'Std':>12} {'Median':>12}")
for col in numeric_cols:
v = df[col]
R.append(f" {col:<18} {v.min():>12.6f} {v.max():>12.6f} {v.mean():>12.6f} {v.std():>12.6f} {v.median():>12.6f}")
# ── Section 2: Parameter Space Coverage ──
R.append("")
R.append("" * 78)
R.append("2. PARAMETER SPACE COVERAGE")
R.append("" * 78)
omega_vals = sorted(df['omega'].unique())
khra_vals = sorted(df['khra_amp'].unique())
gixx_vals = sorted(df['gixx_amp'].unique())
R.append(f" Omega: {len(omega_vals)} values: {[round(x,1) for x in omega_vals]}")
R.append(f" Khra_amp: {len(khra_vals)} values: {[round(x,3) for x in khra_vals]}")
R.append(f" Gixx_amp: {len(gixx_vals)} values: {[round(x,4) for x in gixx_vals]}")
R.append(f" Grid: {len(omega_vals)} × {len(khra_vals)} × {len(gixx_vals)} = {len(omega_vals)*len(khra_vals)*len(gixx_vals)} (actual: {len(df)})")
# ── Section 3: Coherence Analysis ──
R.append("")
R.append("" * 78)
R.append("3. COHERENCE ANALYSIS")
R.append("" * 78)
# Top 10 coherence values
top10 = df.nlargest(10, 'coherence')
R.append(" Top 10 coherence measurements:")
R.append(f" {'Rank':>4} {'Ω':>5} {'K':>6} {'G':>7} {'Coh':>10} {'Asym':>8} {'Vort':>10}")
for rank, (_, row) in enumerate(top10.iterrows(), 1):
R.append(f" {rank:4d} {row['omega']:5.1f} {row['khra_amp']:6.3f} {row['gixx_amp']:7.4f} "
f"{row['coherence']:10.6f} {row['asymmetry']:8.4f} {row['vorticity_mean']:10.6f}")
# Bottom 10
bot10 = df.nsmallest(10, 'coherence')
R.append("\n Bottom 10 coherence measurements:")
R.append(f" {'Rank':>4} {'Ω':>5} {'K':>6} {'G':>7} {'Coh':>10} {'Asym':>8} {'Vort':>10}")
for rank, (_, row) in enumerate(bot10.iterrows(), 1):
R.append(f" {rank:4d} {row['omega']:5.1f} {row['khra_amp']:6.3f} {row['gixx_amp']:7.4f} "
f"{row['coherence']:10.6f} {row['asymmetry']:8.4f} {row['vorticity_mean']:10.6f}")
# ── Section 4: Per-Omega Breakdown ──
R.append("")
R.append("" * 78)
R.append("4. PER-OMEGA BREAKDOWN")
R.append("" * 78)
R.append(f" {'Ω':>5} {'Coh_min':>10} {'Coh_max':>10} {'Coh_mean':>10} {'Coh_std':>10} "
f"{'Asym_mean':>10} {'Vort_mean':>10} {'Best K':>7} {'Best G':>8}")
for omega in omega_vals:
g = df[df['omega'] == omega]
best = g.loc[g['coherence'].idxmax()]
R.append(f" {omega:5.1f} {g['coherence'].min():10.6f} {g['coherence'].max():10.6f} "
f"{g['coherence'].mean():10.6f} {g['coherence'].std():10.6f} "
f"{g['asymmetry'].mean():10.4f} {g['vorticity_mean'].mean():10.6f} "
f"{best['khra_amp']:7.3f} {best['gixx_amp']:8.4f}")
# ── Section 5: Per-Khra Breakdown ──
R.append("")
R.append("" * 78)
R.append("5. PER-KHRA BREAKDOWN")
R.append("" * 78)
R.append(f" {'K':>6} {'Coh_min':>10} {'Coh_max':>10} {'Coh_mean':>10} {'Coh_std':>10} {'Best Ω':>6} {'Best G':>8}")
for khra in khra_vals:
g = df[df['khra_amp'] == khra]
best = g.loc[g['coherence'].idxmax()]
R.append(f" {khra:6.3f} {g['coherence'].min():10.6f} {g['coherence'].max():10.6f} "
f"{g['coherence'].mean():10.6f} {g['coherence'].std():10.6f} "
f"{best['omega']:6.1f} {best['gixx_amp']:8.4f}")
# ── Section 6: Per-Gixx Breakdown ──
R.append("")
R.append("" * 78)
R.append("6. PER-GIXX BREAKDOWN")
R.append("" * 78)
R.append(f" {'G':>7} {'Coh_min':>10} {'Coh_max':>10} {'Coh_mean':>10} {'Coh_std':>10} {'Best Ω':>6} {'Best K':>7}")
for gixx in gixx_vals:
g = df[df['gixx_amp'] == gixx]
best = g.loc[g['coherence'].idxmax()]
R.append(f" {gixx:7.4f} {g['coherence'].min():10.6f} {g['coherence'].max():10.6f} "
f"{g['coherence'].mean():10.6f} {g['coherence'].std():10.6f} "
f"{best['omega']:6.1f} {best['khra_amp']:7.3f}")
# ── Section 7: Correlation Matrix ──
R.append("")
R.append("" * 78)
R.append("7. CORRELATION MATRIX")
R.append("" * 78)
corr_cols = ['omega', 'khra_amp', 'gixx_amp', 'coherence', 'asymmetry', 'vorticity_mean']
corr = df[corr_cols].corr()
R.append(f" {'':>14}" + "".join(f"{c:>14}" for c in corr_cols))
for row_name in corr_cols:
vals = "".join(f"{corr.loc[row_name, c]:14.4f}" for c in corr_cols)
R.append(f" {row_name:>14}{vals}")
# ── Section 8: Coherence Sensitivity ──
R.append("")
R.append("" * 78)
R.append("8. PARAMETER SENSITIVITY (effect on coherence)")
R.append("" * 78)
# Omega sensitivity: variance of mean coherence across omega
omega_means = df.groupby('omega')['coherence'].mean()
khra_means = df.groupby('khra_amp')['coherence'].mean()
gixx_means = df.groupby('gixx_amp')['coherence'].mean()
omega_range = omega_means.max() - omega_means.min()
khra_range = khra_means.max() - khra_means.min()
gixx_range = gixx_means.max() - gixx_means.min()
total_range = omega_range + khra_range + gixx_range
R.append(f" Omega effect: range={omega_range:.6f} ({100*omega_range/total_range:.1f}% of total)")
R.append(f" Khra effect: range={khra_range:.6f} ({100*khra_range/total_range:.1f}% of total)")
R.append(f" Gixx effect: range={gixx_range:.6f} ({100*gixx_range/total_range:.1f}% of total)")
R.append(f" Most influential: {'omega' if omega_range >= max(khra_range, gixx_range) else 'khra_amp' if khra_range >= gixx_range else 'gixx_amp'}")
# Per-omega sensitivity to khra and gixx
R.append(f"\n Per-omega sensitivity (coherence std when varying K,G):")
R.append(f" {'Ω':>5} {'Std(coh)':>10} {'Sensitivity':>12}")
for omega in omega_vals:
g = df[df['omega'] == omega]
s = g['coherence'].std()
bar = "" * int(s * 10000)
R.append(f" {omega:5.1f} {s:10.6f} {bar}")
# ── Section 9: Thermal & Power Profile ──
R.append("")
R.append("" * 78)
R.append("9. THERMAL & POWER PROFILE")
R.append("" * 78)
R.append(f" GPU Temperature:")
R.append(f" Min: {df['gpu_temp_c'].min():.0f}°C Max: {df['gpu_temp_c'].max():.0f}°C Mean: {df['gpu_temp_c'].mean():.1f}°C")
R.append(f" Points above 60°C: {(df['gpu_temp_c'] > 60).sum()} ({100*(df['gpu_temp_c'] > 60).mean():.1f}%)")
R.append(f" GPU Power:")
R.append(f" Min: {df['gpu_power_w'].min():.1f}W Max: {df['gpu_power_w'].max():.1f}W Mean: {df['gpu_power_w'].mean():.1f}W")
R.append(f" High power (>250W): {(df['gpu_power_w'] > 250).sum()} ({100*(df['gpu_power_w'] > 250).mean():.1f}%)")
R.append(f" Idle (<100W): {(df['gpu_power_w'] < 100).sum()} ({100*(df['gpu_power_w'] < 100).mean():.1f}%)")
# Temperature by omega
R.append(f"\n Temperature by omega:")
R.append(f" {'Ω':>5} {'Temp_mean':>10} {'Power_mean':>11}")
for omega in omega_vals:
g = df[df['omega'] == omega]
R.append(f" {omega:5.1f} {g['gpu_temp_c'].mean():10.1f} {g['gpu_power_w'].mean():11.1f}")
# ── Section 10: Asymmetry & Vorticity Analysis ──
R.append("")
R.append("" * 78)
R.append("10. ASYMMETRY & VORTICITY ANALYSIS")
R.append("" * 78)
R.append(f" Asymmetry: min={df['asymmetry'].min():.4f} max={df['asymmetry'].max():.4f} mean={df['asymmetry'].mean():.4f}")
R.append(f" Vorticity: min={df['vorticity_mean'].min():.6f} max={df['vorticity_mean'].max():.6f} mean={df['vorticity_mean'].mean():.6f}")
# Best asymmetry (lowest = most symmetric)
best_sym = df.nsmallest(5, 'asymmetry')
R.append(f"\n Most symmetric configurations (lowest asymmetry):")
for _, row in best_sym.iterrows():
R.append(f" Ω={row['omega']:.1f} K={row['khra_amp']:.3f} G={row['gixx_amp']:.4f} "
f"Asym={row['asymmetry']:.4f} Coh={row['coherence']:.6f}")
# Highest vorticity
high_vort = df.nlargest(5, 'vorticity_mean')
R.append(f"\n Highest vorticity configurations:")
for _, row in high_vort.iterrows():
R.append(f" Ω={row['omega']:.1f} K={row['khra_amp']:.3f} G={row['gixx_amp']:.4f} "
f"Vort={row['vorticity_mean']:.6f} Coh={row['coherence']:.6f}")
# Coherence-Asymmetry relationship
coh_asym_corr = df['coherence'].corr(df['asymmetry'])
coh_vort_corr = df['coherence'].corr(df['vorticity_mean'])
asym_vort_corr = df['asymmetry'].corr(df['vorticity_mean'])
R.append(f"\n Cross-correlations:")
R.append(f" Coherence ↔ Asymmetry: {coh_asym_corr:+.4f}")
R.append(f" Coherence ↔ Vorticity: {coh_vort_corr:+.4f}")
R.append(f" Asymmetry ↔ Vorticity: {asym_vort_corr:+.4f}")
# ── Section 11: Optimal Operating Regions ──
R.append("")
R.append("" * 78)
R.append("11. OPTIMAL OPERATING REGIONS")
R.append("" * 78)
# Multi-objective: high coherence + low asymmetry
df_copy = df.copy()
df_copy['score'] = (df_copy['coherence'] - df_copy['coherence'].min()) / (df_copy['coherence'].max() - df_copy['coherence'].min()) - \
0.5 * (df_copy['asymmetry'] - df_copy['asymmetry'].min()) / (df_copy['asymmetry'].max() - df_copy['asymmetry'].min())
best_multi = df_copy.nlargest(10, 'score')
R.append(f" Top 10 by composite score (high coherence + low asymmetry):")
R.append(f" {'Ω':>5} {'K':>6} {'G':>7} {'Coh':>10} {'Asym':>8} {'Vort':>10} {'Score':>8}")
for _, row in best_multi.iterrows():
R.append(f" {row['omega']:5.1f} {row['khra_amp']:6.3f} {row['gixx_amp']:7.4f} "
f"{row['coherence']:10.6f} {row['asymmetry']:8.4f} {row['vorticity_mean']:10.6f} {row['score']:8.4f}")
# Recommend optimal settings
best_overall = best_multi.iloc[0]
R.append(f"\n ★ RECOMMENDED OPERATING POINT:")
R.append(f" Ω = {best_overall['omega']:.1f}")
R.append(f" khra_amp = {best_overall['khra_amp']:.3f}")
R.append(f" gixx_amp = {best_overall['gixx_amp']:.4f}")
R.append(f" Expected coherence: {best_overall['coherence']:.6f}")
R.append(f" Expected asymmetry: {best_overall['asymmetry']:.4f}")
# ── Section 12: Data Quality Assessment ──
R.append("")
R.append("" * 78)
R.append("12. DATA QUALITY ASSESSMENT")
R.append("" * 78)
# Check for duplicate telemetry (stale reads)
# Count consecutive identical coherence values
coh_vals = df['coherence'].values
stale_runs = []
run_len = 1
for i in range(1, len(coh_vals)):
if coh_vals[i] == coh_vals[i-1]:
run_len += 1
else:
if run_len > 1:
stale_runs.append(run_len)
run_len = 1
if run_len > 1:
stale_runs.append(run_len)
total_stale = sum(stale_runs)
R.append(f" Consecutive identical readings: {len(stale_runs)} runs")
R.append(f" Total stale points: {total_stale}/{len(df)} ({100*total_stale/len(df):.1f}%)")
if stale_runs:
R.append(f" Longest stale run: {max(stale_runs)} points")
R.append(f" Mean stale run length: {np.mean(stale_runs):.1f}")
# Unique coherence values
n_unique = df['coherence'].nunique()
R.append(f" Unique coherence values: {n_unique}/{len(df)} ({100*n_unique/len(df):.1f}%)")
# Check cycle progression
cycles = df['cycle'].values
cycle_gaps = np.diff(cycles)
R.append(f"\n Cycle progression:")
R.append(f" Start cycle: {int(cycles[0])}")
R.append(f" End cycle: {int(cycles[-1])}")
R.append(f" Total cycles: {int(cycles[-1] - cycles[0])}")
R.append(f" Mean gap: {cycle_gaps.mean():.0f} cycles/point")
R.append(f" Backwards jumps: {(cycle_gaps < 0).sum()}")
R.append("")
R.append("=" * 78)
R.append("END OF REPORT")
R.append("=" * 78)
return "\n".join(R)
# ═══════════════════════════════════════════════════════════════════
# PART 2: Interactive HTML Dashboard
# ═══════════════════════════════════════════════════════════════════
def generate_html_report(df, source_name):
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
omega_vals = sorted(df['omega'].unique())
khra_vals = sorted(df['khra_amp'].unique())
gixx_vals = sorted(df['gixx_amp'].unique())
# Prepare data for JS
# 1. Per-omega stats
omega_stats = []
for omega in omega_vals:
g = df[df['omega'] == omega]
best = g.loc[g['coherence'].idxmax()]
omega_stats.append({
'omega': omega,
'coh_min': round(g['coherence'].min(), 6),
'coh_max': round(g['coherence'].max(), 6),
'coh_mean': round(g['coherence'].mean(), 6),
'coh_std': round(g['coherence'].std(), 6),
'asym_mean': round(g['asymmetry'].mean(), 4),
'vort_mean': round(g['vorticity_mean'].mean(), 6),
'temp_mean': round(g['gpu_temp_c'].mean(), 1),
'power_mean': round(g['gpu_power_w'].mean(), 1),
'best_k': round(best['khra_amp'], 3),
'best_g': round(best['gixx_amp'], 4),
})
# 2. Heatmap data: omega × khra → max coherence (across gixx)
heatmap_ok = []
for omega in omega_vals:
row = []
for khra in khra_vals:
g = df[(df['omega'] == omega) & (df['khra_amp'] == khra)]
row.append(round(g['coherence'].max(), 6))
heatmap_ok.append(row)
# 3. Heatmap: omega × gixx → max coherence (across khra)
heatmap_og = []
for omega in omega_vals:
row = []
for gixx in gixx_vals:
g = df[(df['omega'] == omega) & (df['gixx_amp'] == gixx)]
row.append(round(g['coherence'].max(), 6))
heatmap_og.append(row)
# 4. All data points for scatter
scatter_data = []
for _, row in df.iterrows():
scatter_data.append({
'o': round(row['omega'], 1),
'k': round(row['khra_amp'], 3),
'g': round(row['gixx_amp'], 4),
'c': round(row['coherence'], 6),
'a': round(row['asymmetry'], 4),
'v': round(row['vorticity_mean'], 6),
't': int(row['gpu_temp_c']),
'p': round(row['gpu_power_w'], 1),
})
# 5. Coherence distribution histogram
coh_vals = df['coherence'].values
hist_bins = 30
hist_counts, hist_edges = np.histogram(coh_vals, bins=hist_bins)
hist_centers = [round(0.5*(hist_edges[i] + hist_edges[i+1]), 6) for i in range(hist_bins)]
# 6. Top configurations
top20 = df.nlargest(20, 'coherence')
top_configs = []
for _, row in top20.iterrows():
top_configs.append({
'omega': round(row['omega'], 1),
'khra': round(row['khra_amp'], 3),
'gixx': round(row['gixx_amp'], 4),
'coh': round(row['coherence'], 6),
'asym': round(row['asymmetry'], 4),
'vort': round(row['vorticity_mean'], 6),
})
# 7. Nuclear magic analysis data
resolution = df['coherence'].std() * 0.1
if resolution < 1e-6:
resolution = 1e-4
mode_counts = {}
for omega in omega_vals:
g = df[df['omega'] == omega]
coh_sorted = np.sort(g['coherence'].values)
modes = [coh_sorted[0]]
for c in coh_sorted[1:]:
if c - modes[-1] > resolution:
modes.append(c)
mode_counts[round(omega, 1)] = len(modes)
html = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Resonance Engine — Sweep Analysis Dashboard</title>
<style>
:root {{
--bg: #0a0e17;
--card: #111827;
--border: #1f2937;
--text: #e5e7eb;
--dim: #9ca3af;
--accent: #60a5fa;
--gold: #fbbf24;
--green: #34d399;
--red: #f87171;
--purple: #a78bfa;
}}
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
body {{ background: var(--bg); color: var(--text); font-family: 'Segoe UI', system-ui, sans-serif; padding: 20px; }}
h1 {{ text-align: center; font-size: 1.8em; margin: 20px 0 5px; color: var(--accent); }}
.subtitle {{ text-align: center; color: var(--dim); margin-bottom: 30px; font-size: 0.9em; }}
.grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(450px, 1fr)); gap: 20px; margin-bottom: 20px; }}
.card {{ background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; }}
.card h2 {{ color: var(--gold); font-size: 1.1em; margin-bottom: 15px; border-bottom: 1px solid var(--border); padding-bottom: 8px; }}
.stat-grid {{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }}
.stat {{ background: var(--bg); padding: 12px; border-radius: 8px; text-align: center; }}
.stat .label {{ color: var(--dim); font-size: 0.75em; margin-bottom: 4px; }}
.stat .value {{ font-size: 1.4em; font-weight: bold; color: var(--accent); }}
.stat .value.gold {{ color: var(--gold); }}
.stat .value.green {{ color: var(--green); }}
canvas {{ width: 100% !important; height: auto !important; }}
table {{ width: 100%; border-collapse: collapse; font-size: 0.85em; }}
th {{ background: var(--bg); padding: 8px 6px; text-align: right; color: var(--gold); position: sticky; top: 0; }}
td {{ padding: 6px; text-align: right; border-bottom: 1px solid var(--border); }}
tr:hover td {{ background: rgba(96,165,250,0.08); }}
.highlight {{ color: var(--green); font-weight: bold; }}
.heatmap-container {{ overflow-x: auto; }}
.heatmap {{ border-collapse: collapse; margin: 0 auto; }}
.heatmap td {{ width: 60px; height: 32px; text-align: center; font-size: 0.75em; font-weight: bold; border: 1px solid var(--bg); }}
.heatmap th {{ padding: 4px 8px; font-size: 0.8em; color: var(--dim); }}
.magic-bar {{ display: flex; align-items: center; gap: 8px; margin: 4px 0; }}
.magic-bar .bar {{ height: 20px; background: var(--accent); border-radius: 4px; transition: width 0.3s; }}
.magic-bar .label {{ font-size: 0.8em; color: var(--dim); min-width: 40px; }}
.magic-bar .count {{ font-size: 0.8em; min-width: 20px; }}
.magic-hit {{ background: var(--gold) !important; color: #000 !important; }}
.full-width {{ grid-column: 1 / -1; }}
.recommend {{ background: linear-gradient(135deg, #1a2744, #1a3a2a); border: 2px solid var(--green); }}
.recommend h2 {{ color: var(--green); }}
.tab-bar {{ display: flex; gap: 4px; margin-bottom: 12px; }}
.tab {{ padding: 6px 14px; border-radius: 6px 6px 0 0; cursor: pointer; background: var(--bg); color: var(--dim); border: 1px solid var(--border); border-bottom: none; font-size: 0.85em; }}
.tab.active {{ background: var(--card); color: var(--accent); }}
.tab-content {{ display: none; }}
.tab-content.active {{ display: block; }}
</style>
</head>
<body>
<h1>⚛ Resonance Engine — Parameter Sweep Dashboard</h1>
<div class="subtitle">{source_name} &bull; {len(df)} points &bull; {ts}</div>
<!-- Key Metrics -->
<div class="grid">
<div class="card full-width">
<h2>Key Metrics</h2>
<div class="stat-grid">
<div class="stat"><div class="label">Peak Coherence</div><div class="value gold">{df['coherence'].max():.6f}</div></div>
<div class="stat"><div class="label">Mean Coherence</div><div class="value">{df['coherence'].mean():.6f}</div></div>
<div class="stat"><div class="label">Coherence Range</div><div class="value">{df['coherence'].max()-df['coherence'].min():.6f}</div></div>
<div class="stat"><div class="label">Best Omega</div><div class="value green">{top_configs[0]['omega']:.1f}</div></div>
<div class="stat"><div class="label">Points</div><div class="value">{len(df)}</div></div>
<div class="stat"><div class="label">Magic Matches</div><div class="value gold">{sum(1 for n in mode_counts.values() if n in MAGIC_NUMBERS)}/15</div></div>
</div>
</div>
</div>
<div class="grid">
<!-- Coherence vs Omega -->
<div class="card">
<h2>Coherence vs Omega</h2>
<canvas id="chartOmega" height="280"></canvas>
</div>
<!-- Coherence Distribution -->
<div class="card">
<h2>Coherence Distribution</h2>
<canvas id="chartHist" height="280"></canvas>
</div>
<!-- Heatmap: Omega × Khra -->
<div class="card">
<h2>Heatmap: Ω × Khra → Peak Coherence</h2>
<div class="heatmap-container" id="heatmapOK"></div>
</div>
<!-- Heatmap: Omega × Gixx -->
<div class="card">
<h2>Heatmap: Ω × Gixx → Peak Coherence</h2>
<div class="heatmap-container" id="heatmapOG"></div>
</div>
<!-- Nuclear Magic Modes -->
<div class="card">
<h2>Mode Count vs Nuclear Magic Numbers</h2>
<canvas id="chartMagic" height="280"></canvas>
<div id="magicBars" style="margin-top:12px;"></div>
</div>
<!-- Asymmetry & Vorticity -->
<div class="card">
<h2>Asymmetry & Vorticity vs Omega</h2>
<canvas id="chartAsymVort" height="280"></canvas>
</div>
<!-- Thermal Profile -->
<div class="card">
<h2>Thermal & Power Profile</h2>
<canvas id="chartThermal" height="280"></canvas>
</div>
<!-- Recommended Config -->
<div class="card recommend">
<h2>★ Recommended Operating Point</h2>
<div class="stat-grid" style="margin-top:10px;">
<div class="stat"><div class="label">Omega (Ω)</div><div class="value green">{top_configs[0]['omega']:.1f}</div></div>
<div class="stat"><div class="label">Khra Amp</div><div class="value green">{top_configs[0]['khra']:.3f}</div></div>
<div class="stat"><div class="label">Gixx Amp</div><div class="value green">{top_configs[0]['gixx']:.4f}</div></div>
</div>
<div class="stat-grid" style="margin-top:10px;">
<div class="stat"><div class="label">Coherence</div><div class="value gold">{top_configs[0]['coh']:.6f}</div></div>
<div class="stat"><div class="label">Asymmetry</div><div class="value">{top_configs[0]['asym']:.4f}</div></div>
<div class="stat"><div class="label">Vorticity</div><div class="value">{top_configs[0]['vort']:.6f}</div></div>
</div>
</div>
</div>
<!-- Top Configurations Table -->
<div class="grid">
<div class="card full-width">
<h2>Top 20 Configurations</h2>
<table>
<thead><tr><th>#</th><th>Ω</th><th>K</th><th>G</th><th>Coherence</th><th>Asymmetry</th><th>Vorticity</th></tr></thead>
<tbody id="topTable"></tbody>
</table>
</div>
</div>
<!-- Per-Omega Detail Table -->
<div class="grid">
<div class="card full-width">
<h2>Per-Omega Summary</h2>
<table>
<thead><tr><th>Ω</th><th>Coh Min</th><th>Coh Max</th><th>Coh Mean</th><th>Coh Std</th><th>Asym Mean</th><th>Vort Mean</th><th>Best K</th><th>Best G</th></tr></thead>
<tbody id="omegaTable"></tbody>
</table>
</div>
</div>
<script>
// ── Data ──
const omegaStats = {json.dumps(omega_stats)};
const heatmapOK = {json.dumps(heatmap_ok)};
const heatmapOG = {json.dumps(heatmap_og)};
const topConfigs = {json.dumps(top_configs)};
const modeCounts = {json.dumps(mode_counts)};
const histCenters = {json.dumps(hist_centers)};
const histCounts = {json.dumps(hist_counts.tolist())};
const omegaLabels = {json.dumps([round(o,1) for o in omega_vals])};
const khraLabels = {json.dumps([round(k,3) for k in khra_vals])};
const gixxLabels = {json.dumps([round(g,4) for g in gixx_vals])};
const magicNumbers = {json.dumps(MAGIC_NUMBERS[:6])};
// ── Minimal Canvas Chart Library ──
function drawChart(canvasId, config) {{
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
const W = rect.width, H = rect.height;
const pad = {{top: 20, right: 20, bottom: 40, left: 70}};
const pW = W - pad.left - pad.right;
const pH = H - pad.top - pad.bottom;
// Background
ctx.fillStyle = '#0a0e17';
ctx.fillRect(0, 0, W, H);
// Find data bounds
let allY = [];
config.datasets.forEach(ds => ds.data.forEach(v => allY.push(v)));
let yMin = config.yMin !== undefined ? config.yMin : Math.min(...allY);
let yMax = config.yMax !== undefined ? config.yMax : Math.max(...allY);
if (yMin === yMax) {{ yMin -= 0.0001; yMax += 0.0001; }}
const yRange = yMax - yMin;
// Grid lines
ctx.strokeStyle = '#1f2937';
ctx.lineWidth = 1;
for (let i = 0; i <= 5; i++) {{
const y = pad.top + pH - (i/5) * pH;
ctx.beginPath(); ctx.moveTo(pad.left, y); ctx.lineTo(W - pad.right, y); ctx.stroke();
ctx.fillStyle = '#9ca3af';
ctx.font = '11px monospace';
ctx.textAlign = 'right';
ctx.fillText((yMin + (i/5) * yRange).toFixed(config.yDecimals || 4), pad.left - 6, y + 4);
}}
// X labels
ctx.textAlign = 'center';
ctx.fillStyle = '#9ca3af';
config.labels.forEach((lbl, i) => {{
const x = pad.left + (i / (config.labels.length - 1)) * pW;
ctx.fillText(lbl, x, H - pad.bottom + 18);
}});
// Axis labels
if (config.xLabel) {{
ctx.fillText(config.xLabel, pad.left + pW/2, H - 4);
}}
// Datasets
config.datasets.forEach(ds => {{
ctx.strokeStyle = ds.color || '#60a5fa';
ctx.lineWidth = ds.lineWidth || 2;
ctx.beginPath();
ds.data.forEach((v, i) => {{
const x = pad.left + (i / (ds.data.length - 1)) * pW;
const y = pad.top + pH - ((v - yMin) / yRange) * pH;
if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
}});
ctx.stroke();
// Points
if (ds.points !== false) {{
ctx.fillStyle = ds.color || '#60a5fa';
ds.data.forEach((v, i) => {{
const x = pad.left + (i / (ds.data.length - 1)) * pW;
const y = pad.top + pH - ((v - yMin) / yRange) * pH;
ctx.beginPath(); ctx.arc(x, y, 4, 0, Math.PI * 2); ctx.fill();
}});
}}
// Label
if (ds.label) {{
ctx.fillStyle = ds.color || '#60a5fa';
ctx.textAlign = 'left';
ctx.font = '11px sans-serif';
const lastY = pad.top + pH - ((ds.data[ds.data.length-1] - yMin) / yRange) * pH;
ctx.fillText(ds.label, W - pad.right + 4, lastY + 4);
}}
}});
// Magic number horizontal lines
if (config.magicLines) {{
ctx.setLineDash([4, 4]);
ctx.strokeStyle = '#fbbf2480';
ctx.lineWidth = 1;
magicNumbers.forEach(mn => {{
if (mn >= yMin && mn <= yMax) {{
const y = pad.top + pH - ((mn - yMin) / yRange) * pH;
ctx.beginPath(); ctx.moveTo(pad.left, y); ctx.lineTo(W-pad.right, y); ctx.stroke();
ctx.fillStyle = '#fbbf24';
ctx.textAlign = 'right';
ctx.fillText(mn, pad.left - 4, y + 4);
}}
}});
ctx.setLineDash([]);
}}
}}
function drawBarChart(canvasId, labels, data, color, yLabel) {{
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
const W = rect.width, H = rect.height;
const pad = {{top: 20, right: 20, bottom: 40, left: 60}};
const pW = W - pad.left - pad.right;
const pH = H - pad.top - pad.bottom;
ctx.fillStyle = '#0a0e17';
ctx.fillRect(0, 0, W, H);
const maxVal = Math.max(...data) * 1.1;
const barW = pW / data.length * 0.7;
const gap = pW / data.length * 0.3;
data.forEach((v, i) => {{
const x = pad.left + (i / data.length) * pW + gap/2;
const barH = (v / maxVal) * pH;
const y = pad.top + pH - barH;
ctx.fillStyle = color || '#60a5fa';
ctx.fillRect(x, y, barW, barH);
ctx.fillStyle = '#9ca3af';
ctx.font = '10px monospace';
ctx.textAlign = 'center';
ctx.fillText(labels[i], x + barW/2, H - pad.bottom + 16);
}});
// Y axis
for (let i = 0; i <= 4; i++) {{
const y = pad.top + pH - (i/4) * pH;
ctx.strokeStyle = '#1f2937';
ctx.beginPath(); ctx.moveTo(pad.left, y); ctx.lineTo(W-pad.right, y); ctx.stroke();
ctx.fillStyle = '#9ca3af';
ctx.textAlign = 'right';
ctx.font = '11px monospace';
ctx.fillText((maxVal * i / 4).toFixed(0), pad.left - 6, y + 4);
}}
}}
// ── Render Charts ──
window.addEventListener('load', () => {{
// Coherence vs Omega
drawChart('chartOmega', {{
labels: omegaLabels,
xLabel: 'Omega (Ω)',
yDecimals: 4,
datasets: [
{{ data: omegaStats.map(s => s.coh_max), color: '#fbbf24', label: 'Max', lineWidth: 2 }},
{{ data: omegaStats.map(s => s.coh_mean), color: '#60a5fa', label: 'Mean', lineWidth: 2 }},
{{ data: omegaStats.map(s => s.coh_min), color: '#f87171', label: 'Min', lineWidth: 1 }},
]
}});
// Histogram
drawBarChart('chartHist', histCenters.map(c => c.toFixed(4)), histCounts, '#60a5fa');
// Mode counts with magic lines
drawChart('chartMagic', {{
labels: omegaLabels,
xLabel: 'Omega (Ω)',
yDecimals: 0,
yMin: 0,
yMax: 30,
magicLines: true,
datasets: [
{{ data: omegaLabels.map(o => modeCounts[o]), color: '#34d399', label: 'Modes', lineWidth: 2 }},
]
}});
// Asymmetry & Vorticity
drawChart('chartAsymVort', {{
labels: omegaLabels,
xLabel: 'Omega (Ω)',
yDecimals: 2,
datasets: [
{{ data: omegaStats.map(s => s.asym_mean), color: '#a78bfa', label: 'Asymmetry' }},
]
}});
// Thermal
drawChart('chartThermal', {{
labels: omegaLabels,
xLabel: 'Omega (Ω)',
yDecimals: 0,
datasets: [
{{ data: omegaStats.map(s => s.temp_mean), color: '#f87171', label: 'Temp °C' }},
{{ data: omegaStats.map(s => s.power_mean / 5), color: '#fbbf24', label: 'Power/5' }},
]
}});
// Heatmaps
renderHeatmap('heatmapOK', heatmapOK, omegaLabels, khraLabels, 'Ω', 'K');
renderHeatmap('heatmapOG', heatmapOG, omegaLabels, gixxLabels, 'Ω', 'G');
// Tables
renderTopTable();
renderOmegaTable();
}});
function renderHeatmap(containerId, data, rowLabels, colLabels, rowName, colName) {{
const container = document.getElementById(containerId);
const allVals = data.flat();
const vMin = Math.min(...allVals);
const vMax = Math.max(...allVals);
const range = vMax - vMin || 0.0001;
let html = '<table class="heatmap"><tr><th>' + rowName + '\\\\' + colName + '</th>';
colLabels.forEach(c => html += '<th>' + c + '</th>');
html += '</tr>';
data.forEach((row, i) => {{
html += '<tr><th>' + rowLabels[i] + '</th>';
row.forEach(v => {{
const t = (v - vMin) / range;
const r = Math.round(30 + 50 * (1-t));
const g = Math.round(80 + 160 * t);
const b = Math.round(120 + 130 * t);
html += '<td style="background:rgb(' + r + ',' + g + ',' + b + ');color:' + (t > 0.5 ? '#000' : '#fff') + '">' + v.toFixed(4) + '</td>';
}});
html += '</tr>';
}});
html += '</table>';
container.innerHTML = html;
}}
function renderTopTable() {{
const tbody = document.getElementById('topTable');
topConfigs.forEach((c, i) => {{
tbody.innerHTML += '<tr><td>' + (i+1) + '</td><td>' + c.omega + '</td><td>' + c.khra + '</td><td>' + c.gixx + '</td><td class="highlight">' + c.coh.toFixed(6) + '</td><td>' + c.asym + '</td><td>' + c.vort + '</td></tr>';
}});
}}
function renderOmegaTable() {{
const tbody = document.getElementById('omegaTable');
omegaStats.forEach(s => {{
tbody.innerHTML += '<tr><td>' + s.omega + '</td><td>' + s.coh_min.toFixed(6) + '</td><td>' + s.coh_max.toFixed(6) + '</td><td>' + s.coh_mean.toFixed(6) + '</td><td>' + s.coh_std.toFixed(6) + '</td><td>' + s.asym_mean + '</td><td>' + s.vort_mean + '</td><td>' + s.best_k + '</td><td>' + s.best_g + '</td></tr>';
}});
}}
</script>
</body>
</html>"""
return html
# ═══════════════════════════════════════════════════════════════════
# Main
# ═══════════════════════════════════════════════════════════════════
def main():
csv_path = sys.argv[1] if len(sys.argv) > 1 else None
df, source = load_data(csv_path)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# Generate text report
print("Generating text report...")
text_report = generate_text_report(df, source)
text_path = os.path.join(RESULTS_DIR, f"sweep_analysis_{timestamp}.txt")
with open(text_path, 'w', encoding='utf-8') as f:
f.write(text_report)
print(f" Saved: {text_path}")
# Generate HTML dashboard
print("Generating HTML dashboard...")
html_report = generate_html_report(df, source)
html_path = os.path.join(RESULTS_DIR, f"sweep_dashboard_{timestamp}.html")
with open(html_path, 'w', encoding='utf-8') as f:
f.write(html_report)
print(f" Saved: {html_path}")
# Print summary to stdout
print("\n" + text_report)
if __name__ == "__main__":
main()