Files
Atomizer/.claude/skills/generate-report.md
Antoine fb2d06236a feat: Improve dashboard layout and Claude terminal context
- Reorganize dashboard: control panel on top, charts stacked vertically
- Add Set Context button to Claude terminal for study awareness
- Add conda environment instructions to CLAUDE.md
- Fix STUDY_REPORT.md location in generate-report.md skill
- Claude terminal now sends study context with skills reminder

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 20:59:31 -05:00

12 KiB

Generate Report Skill

Last Updated: December 3, 2025 Version: 1.1 - Optimization Results Analysis and Reporting (Dashboard Integration)

You are helping the user understand and communicate optimization results.

Purpose

Generate comprehensive reports from completed optimization studies:

  1. Pareto front analysis and visualization
  2. Design space exploration insights
  3. Constraint satisfaction analysis
  4. Engineering recommendations
  5. Export-ready summaries

Triggers

  • "generate report"
  • "show results"
  • "analyze the optimization"
  • "what did we find?"
  • "summarize the study"
  • "export results"

Prerequisites

  • Completed optimization study with study.db
  • At least 10 completed trials (for meaningful analysis)
  • Optional: optimization_config.json for context

Report Types

1. Quick Summary

Fast overview of key findings (default).

2. Full Technical Report

Comprehensive analysis with all visualizations.

3. Executive Summary

High-level findings for stakeholders.

4. Export Package

Data files for external analysis.

Execution Steps

Step 1: Load Study Data

import optuna
import json
from pathlib import Path

def load_study_data(study_name: str):
    """Load all optimization data for analysis."""
    study_dir = Path(f"studies/{study_name}")

    # Load Optuna study
    storage = f"sqlite:///{study_dir / '2_results' / 'study.db'}"
    study = optuna.load_study(study_name=study_name, storage=storage)

    # Load config for context
    config_path = study_dir / "1_setup" / "optimization_config.json"
    config = json.loads(config_path.read_text()) if config_path.exists() else {}

    return {
        'study': study,
        'config': config,
        'n_trials': len(study.trials),
        'n_completed': len([t for t in study.trials if t.state == optuna.trial.TrialState.COMPLETE]),
        'is_multi_objective': len(study.directions) > 1
    }

Step 2: Analyze Results

For Multi-Objective (Pareto Analysis)

def analyze_pareto_front(study):
    """Extract and analyze Pareto-optimal solutions."""
    pareto_trials = study.best_trials

    results = {
        'n_pareto': len(pareto_trials),
        'designs': [],
        'ranges': {},
        'trade_offs': []
    }

    for trial in pareto_trials:
        design = {
            'trial_number': trial.number,
            'objectives': trial.values,
            'parameters': trial.params,
            'user_attrs': trial.user_attrs
        }
        results['designs'].append(design)

    # Calculate objective ranges on Pareto front
    if pareto_trials:
        obj_names = ['mass', 'frequency']  # From config
        for i, name in enumerate(obj_names):
            values = [t.values[i] for t in pareto_trials]
            results['ranges'][name] = {
                'min': min(values),
                'max': max(values),
                'spread': max(values) - min(values)
            }

    return results

For Single-Objective

def analyze_single_objective(study):
    """Analyze single-objective optimization results."""
    best = study.best_trial

    return {
        'best_value': best.value,
        'best_params': best.params,
        'convergence': get_convergence_history(study),
        'improvement_rate': calculate_improvement_rate(study)
    }

Step 3: Constraint Analysis

def analyze_constraints(study, config):
    """Analyze constraint satisfaction across trials."""
    constraints = config.get('constraints', [])

    results = {
        'total_trials': len(study.trials),
        'feasible': 0,
        'infeasible': 0,
        'violations': {}
    }

    for constraint in constraints:
        results['violations'][constraint['name']] = 0

    for trial in study.trials:
        if trial.state != optuna.trial.TrialState.COMPLETE:
            continue

        is_feasible = trial.user_attrs.get('feasible', True)
        if is_feasible:
            results['feasible'] += 1
        else:
            results['infeasible'] += 1
            # Track which constraints were violated
            for constraint in constraints:
                if constraint['name'] in trial.user_attrs.get('violated_constraints', []):
                    results['violations'][constraint['name']] += 1

    results['feasibility_rate'] = results['feasible'] / results['total_trials'] * 100

    return results

Step 4: Generate Visualizations

Describe what plots to generate (actual generation done via Python scripts):

  1. Pareto Front Plot: Mass vs Frequency with feasibility coloring
  2. Parallel Coordinates: All design variables with objective coloring
  3. Parameter Importance: Which variables most affect objectives
  4. Convergence History: Best value over trials
  5. Design Space Coverage: Parameter distributions

Step 5: Generate Report Text

Output Format: Quick Summary

OPTIMIZATION RESULTS: {study_name}
===================================

Study Info:
  Protocol: Protocol 11 (Multi-Objective NSGA-II)
  Trials: 30 completed
  Duration: 14m 23s
  Feasibility Rate: 80%

PARETO FRONT (8 optimal designs)
--------------------------------

| # | Mass (g) | Freq (Hz) | Feasible | Notes |
|---|----------|-----------|----------|-------|
| 1 | 231      | 118       | Yes      | Lightest |
| 2 | 248      | 128       | Yes      | |
| 3 | 265      | 138       | Yes      | Balanced |
| 4 | 282      | 148       | Yes      | |
| 5 | 298      | 156       | Yes      | Stiffest |

Trade-off Summary:
  - Mass range: 231g - 298g (67g spread)
  - Frequency range: 118Hz - 156Hz (38Hz spread)
  - Trade-off rate: ~1.7g per Hz

BEST DESIGNS BY OBJECTIVE
-------------------------

Lightest Design (#1):
  Mass: 231g, Frequency: 118Hz
  Parameters:
    beam_half_core_thickness: 8.2mm
    beam_face_thickness: 1.1mm
    holes_diameter: 42mm
    hole_count: 10

Stiffest Design (#5):
  Mass: 298g, Frequency: 156Hz
  Parameters:
    beam_half_core_thickness: 18.5mm
    beam_face_thickness: 2.8mm
    holes_diameter: 22mm
    hole_count: 6

CONSTRAINT ANALYSIS
-------------------

Constraints checked:
  - max_displacement < 5mm: 24/30 satisfied (80%)
  - max_stress < 200 MPa: 28/30 satisfied (93%)

Most common violation: Displacement (6 trials)
  Occurred when: holes_diameter > 40mm AND face_thickness < 1.5mm

PARAMETER INSIGHTS
------------------

Most influential on mass:
  1. holes_diameter (negative correlation)
  2. beam_face_thickness (positive)
  3. beam_half_core_thickness (positive)

Most influential on frequency:
  1. beam_half_core_thickness (positive)
  2. holes_diameter (negative)
  3. beam_face_thickness (moderate positive)

RECOMMENDATIONS
---------------

1. For lightweight priority:
   - Use larger holes (40-45mm)
   - Minimize face thickness (1.0-1.5mm)
   - Accept frequency around 120Hz

2. For stiffness priority:
   - Use smaller holes (20-25mm)
   - Increase core thickness (18-20mm)
   - Accept mass around 300g

3. Balanced recommendation:
   - Design #3 offers good compromise
   - 265g mass with 138Hz frequency
   - 13% lighter than stiffest, 17% stiffer than lightest

NEXT STEPS
----------

1. Export selected designs: python export_pareto.py --designs 1,3,5
2. Validate in NX: Open model with exported parameters
3. Continue optimization: python run_optimization.py --trials 50 --resume
4. Enable NN acceleration: Add --enable-nn flag for faster exploration

Output Format: Full Technical Report

Generate markdown file with:

# {study_name} Optimization Report

Generated: {timestamp}
Protocol: {protocol}

## Executive Summary
[2-3 paragraph overview]

## Study Configuration
### Design Variables
[Table of variables, bounds, types]

### Objectives
[Table of objectives, goals, targets]

### Constraints
[Table of constraints, thresholds]

## Results Analysis

### Pareto Front
[Detailed table of all Pareto-optimal designs]

![Pareto Front](pareto_front.png)

### Design Space Exploration
[Parallel coordinates plot]

![Parallel Coordinates](parallel_coords.png)

### Convergence History
[Plot of best values over trials]

### Parameter Importance
[SHAP or importance analysis]

## Constraint Satisfaction
[Detailed constraint analysis]

## Engineering Recommendations
[Specific design recommendations]

## Appendix
### All Trial Data
[Exportable CSV reference]

### Methodology Notes
[Protocol details, sampler settings]

Export Package

Generate files:

{study_name}_export/
├── pareto_designs.csv       # All Pareto-optimal designs
├── all_trials.csv           # Complete trial history
├── optimization_summary.json # Machine-readable summary
├── pareto_front.png         # Visualization
├── parallel_coords.png      # Visualization
└── README.md                # Export documentation

Error Handling

Error Recovery
No completed trials Suggest running more trials
No feasible designs Analyze constraint violations
Study not found List available studies
Incomplete data Note missing fields

Integration with Other Skills

  • After report → /export-results for specific designs
  • If poor results → /troubleshoot for analysis
  • To continue → /run-optimization with --resume

Example Conversation

USER: Show me the results for uav_arm_optimization

CLAUDE: I'll generate a report for the UAV arm optimization study...

[Loads study data]

OPTIMIZATION RESULTS: uav_arm_optimization
==========================================

Found 30 completed trials with 8 Pareto-optimal designs.

PARETO FRONT SUMMARY
--------------------
| Design | Mass (g) | Freq (Hz) | Trade-off |
|--------|----------|-----------|-----------|
| #1     | 231      | 118       | Lightest  |
| #3     | 265      | 138       | Balanced  |
| #5     | 298      | 156       | Stiffest  |

Key Finding: You can save 67g (23%) by accepting 38Hz (24%)
lower frequency.

RECOMMENDATION: Design #3 (265g, 138Hz) offers the best balance
for a camera gimbal application where both vibration and weight
matter.

Would you like me to:
1. Generate a full technical report with visualizations?
2. Export the top designs for validation in NX?
3. Continue optimization to explore more designs?

Dashboard Integration (December 2025)

When a STUDY_REPORT.md file is generated, it can be viewed directly in the Atomizer Dashboard:

  1. Save report to: studies/{study_name}/STUDY_REPORT.md (study root folder)
  2. View in dashboard: Click "Study Report" button on the dashboard
  3. Features:
    • Full markdown rendering with proper typography
    • Math equation support via KaTeX ($...$ inline, $$...$$ block)
    • Tables, code blocks, task lists
    • Live refresh button for updates during analysis

Report Format for Dashboard

Use standard markdown with optional LaTeX math:

# Study Report: {study_name}

## Summary

The optimization achieved a **{improvement}%** improvement in objective.

## Results

| Trial | Objective | Improvement |
|-------|-----------|-------------|
| 0     | 100.0     | baseline    |
| 10    | 85.5      | 14.5%       |

## Mathematical Formulation

The RMS wavefront error is calculated as:

$$\text{RMS} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}c_i^2}$$

where $c_i$ are the Zernike coefficients.

Notes

  • Reports should be actionable, not just data dumps
  • Always provide engineering context and recommendations
  • Consider the user's stated goals when highlighting results
  • Visualizations should be generated via Python scripts
  • Export formats should be compatible with common tools (Excel, etc.)
  • Use STUDY_REPORT.md for dashboard-viewable reports with math support