# Implementation Guide: Protocol 13 - Real-Time Tracking **Date:** 2025-11-21 **Status:** 🚧 IN PROGRESS **Priority:** P0 - CRITICAL ## What's Done ✅ 1. **Created [`realtime_tracking.py`](../optimization_engine/realtime_tracking.py)** - `RealtimeTrackingCallback` class - Writes JSON files after EVERY trial (atomic writes) - Files: optimizer_state.json, strategy_history.json, trial_log.json, landscape_snapshot.json, confidence_history.json 2. **Fixed Multi-Objective Strategy (Protocol 12)** - Modified [`strategy_selector.py`](../optimization_engine/strategy_selector.py) - Added `_recommend_multiobjective_strategy()` method - Multi-objective: Random (8 trials) → TPE with multivariate ## What's Needed ⚠️ ### Step 1: Integrate Callback into IntelligentOptimizer **File:** [`optimization_engine/intelligent_optimizer.py`](../optimization_engine/intelligent_optimizer.py) **Line 48 - Add import:** ```python from optimization_engine.adaptive_characterization import CharacterizationStoppingCriterion from optimization_engine.realtime_tracking import create_realtime_callback # ADD THIS ``` **Line ~90 in `__init__()` - Create callback:** ```python def __init__(self, study_name: str, study_dir: Path, config: Dict, verbose: bool = True): # ... existing init code ... # Create realtime tracking callback (Protocol 13) self.realtime_callback = create_realtime_callback( tracking_dir=self.tracking_dir, optimizer_ref=self, verbose=self.verbose ) ``` **Find ALL `study.optimize()` calls and add callback:** Search for: `self.study.optimize(` Replace pattern: ```python # BEFORE: self.study.optimize(objective_function, n_trials=check_interval) # AFTER: self.study.optimize( objective_function, n_trials=check_interval, callbacks=[self.realtime_callback] ) ``` **Locations to fix (approximate line numbers):** - Line ~190: Characterization phase - Line ~230: Optimization phase (multiple locations) - Line ~260: Refinement phase - Line ~380: Fallback optimization **CRITICAL:** EVERY `study.optimize()` call must include `callbacks=[self.realtime_callback]` ### Step 2: Test Realtime Tracking ```bash # Clear old results cd studies/bracket_stiffness_optimization_V2 del /Q 2_results\study.db rd /S /Q 2_results\intelligent_optimizer # Run with new code python -B run_optimization.py --trials 10 # Verify files appear IMMEDIATELY after each trial dir 2_results\intelligent_optimizer # Should see: # - optimizer_state.json # - strategy_history.json # - trial_log.json # - landscape_snapshot.json # - confidence_history.json # Check file updates in real-time python -c "import json; print(json.load(open('2_results/intelligent_optimizer/trial_log.json'))[-1])" ``` --- ## Dashboard Implementation Plan ### Backend API Endpoints (Python/FastAPI) **File:** [`atomizer-dashboard/backend/api/routes/optimization.py`](../atomizer-dashboard/backend/api/routes/optimization.py) **Add new endpoints:** ```python @router.get("/studies/{study_id}/metadata") async def get_study_metadata(study_id: str): """Read optimization_config.json for objectives, design vars, units.""" study_dir = find_study_dir(study_id) config_file = study_dir / "optimization_config.json" with open(config_file) as f: config = json.load(f) return { "objectives": config["objectives"], "design_variables": config["design_variables"], "constraints": config.get("constraints", []), "study_name": config["study_name"] } @router.get("/studies/{study_id}/optimizer-state") async def get_optimizer_state(study_id: str): """Read realtime optimizer state from intelligent_optimizer/.""" study_dir = find_study_dir(study_id) state_file = study_dir / "2_results/intelligent_optimizer/optimizer_state.json" if not state_file.exists(): return {"available": False} with open(state_file) as f: state = json.load(f) return {"available": True, **state} @router.get("/studies/{study_id}/pareto-front") async def get_pareto_front(study_id: str): """Get Pareto-optimal solutions for multi-objective studies.""" study_dir = find_study_dir(study_id) db_path = study_dir / "2_results/study.db" storage = optuna.storages.RDBStorage(f"sqlite:///{db_path}") study = optuna.load_study(study_name=study_id, storage=storage) if len(study.directions) == 1: return {"is_multi_objective": False} pareto_trials = study.best_trials return { "is_multi_objective": True, "pareto_front": [ { "trial_number": t.number, "values": t.values, "params": t.params, "user_attrs": dict(t.user_attrs) } for t in pareto_trials ] } ``` ### Frontend Components (React/TypeScript) **1. Optimizer Panel Component** **File:** `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx` (CREATE NEW) ```typescript import { useEffect, useState } from 'react'; import { Card } from './Card'; interface OptimizerState { available: boolean; current_phase?: string; current_strategy?: string; trial_number?: number; total_trials?: number; latest_recommendation?: { strategy: string; confidence: number; reasoning: string; }; } export function OptimizerPanel({ studyId }: { studyId: string }) { const [state, setState] = useState(null); useEffect(() => { const fetchState = async () => { const res = await fetch(`/api/optimization/studies/${studyId}/optimizer-state`); const data = await res.json(); setState(data); }; fetchState(); const interval = setInterval(fetchState, 1000); // Update every second return () => clearInterval(interval); }, [studyId]); if (!state?.available) { return null; } return (
{/* Phase */}
Phase
{state.current_phase || 'Unknown'}
{/* Strategy */}
Current Strategy
{state.current_strategy?.toUpperCase() || 'Unknown'}
{/* Progress */}
Progress
{state.trial_number} / {state.total_trials} trials
{/* Confidence */} {state.latest_recommendation && (
Confidence
{(state.latest_recommendation.confidence * 100).toFixed(0)}%
)} {/* Reasoning */} {state.latest_recommendation && (
Reasoning
{state.latest_recommendation.reasoning}
)}
); } ``` **2. Pareto Front Plot** **File:** `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx` (CREATE NEW) ```typescript import { ScatterChart, Scatter, XAxis, YAxis, CartesianGrid, Tooltip, Cell, ResponsiveContainer } from 'recharts'; interface ParetoData { trial_number: number; values: [number, number]; params: Record; constraint_satisfied?: boolean; } export function ParetoPlot({ paretoData, objectives }: { paretoData: ParetoData[]; objectives: Array<{ name: string; unit?: string }>; }) { if (paretoData.length === 0) { return (
No Pareto front data yet
); } const data = paretoData.map(trial => ({ x: trial.values[0], y: trial.values[1], trial_number: trial.number, feasible: trial.constraint_satisfied !== false })); return ( {data.map((entry, index) => ( ))} ); } ``` **3. Update Dashboard.tsx** **File:** [`atomizer-dashboard/frontend/src/pages/Dashboard.tsx`](../atomizer-dashboard/frontend/src/pages/Dashboard.tsx) Add imports at top: ```typescript import { OptimizerPanel } from '../components/OptimizerPanel'; import { ParetoPlot } from '../components/ParetoPlot'; ``` Add new state: ```typescript const [studyMetadata, setStudyMetadata] = useState(null); const [paretoFront, setParetoFront] = useState([]); ``` Fetch metadata when study selected: ```typescript useEffect(() => { if (selectedStudyId) { fetch(`/api/optimization/studies/${selectedStudyId}/metadata`) .then(res => res.json()) .then(setStudyMetadata); fetch(`/api/optimization/studies/${selectedStudyId}/pareto-front`) .then(res => res.json()) .then(data => { if (data.is_multi_objective) { setParetoFront(data.pareto_front); } }); } }, [selectedStudyId]); ``` Add components to layout: ```typescript {/* Add after metrics grid */}
{paretoFront.length > 0 && ( )}
``` --- ## Testing Checklist - [ ] Realtime callback writes files after EVERY trial - [ ] optimizer_state.json updates in real-time - [ ] Dashboard shows optimizer panel with live updates - [ ] Pareto front appears for multi-objective studies - [ ] Units are dynamic (read from config) - [ ] Multi-objective strategy switches from random → TPE after 8 trials --- ## Next Steps 1. Integrate callback into IntelligentOptimizer (Steps above) 2. Implement backend API endpoints 3. Create frontend components 4. Test end-to-end with bracket study 5. Document as Protocol 13