Phase 4 documentation updates: - CANVAS.md: Add AtomizerSpec v2.0 schema, custom extractors section, spec REST API endpoints, and updated file structure - DASHBOARD.md: Add V3.1 release notes, AtomizerSpec API endpoints, and unified configuration features - CLAUDE.md: Add complete AtomizerSpec v2.0 section with code examples, MCP tools reference, API endpoints, and updated directory structure Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
982 lines
30 KiB
Markdown
982 lines
30 KiB
Markdown
# Atomizer Canvas - Visual Workflow Builder
|
|
|
|
**Last Updated**: January 17, 2026
|
|
**Version**: 3.1 (AtomizerSpec v2.0)
|
|
**Status**: Production
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The Atomizer Canvas is a visual, node-based workflow builder for designing optimization studies. It provides a drag-and-drop interface for configuring FEA optimizations that integrates with Claude to validate and execute workflows.
|
|
|
|
**New in v3.1**: The Canvas now uses **AtomizerSpec v2.0** as the unified configuration format. All studies are defined by a single `atomizer_spec.json` file that serves as the single source of truth for Canvas, Backend, Claude, and the Optimization Engine.
|
|
|
|
### Key Features
|
|
|
|
- **Visual Workflow Design**: Drag-and-drop nodes to build optimization pipelines
|
|
- **Professional Lucide Icons**: Clean, consistent iconography throughout the interface
|
|
- **AtomizerSpec v2.0**: Unified JSON spec format (`atomizer_spec.json`) for all configuration
|
|
- **Auto-Load from Studies**: Import existing studies (supports both v2.0 specs and legacy configs)
|
|
- **NX Model Introspection**: Automatically extract expressions from .prt/.sim/.fem files
|
|
- **File Browser**: Browse and select model files with type filtering
|
|
- **Expression Search**: Searchable dropdown for design variable configuration
|
|
- **One-Click Add**: Add discovered expressions as design variables instantly
|
|
- **Custom Extractors**: Define custom Python extraction functions directly in the spec
|
|
- **Claude Integration**: "Process with Claude" button for AI-assisted study creation
|
|
- **Real-time Sync**: WebSocket-based synchronization between clients
|
|
- **Responsive Layout**: Full-screen canvas that adapts to window size
|
|
|
|
### What's New in V3.1
|
|
|
|
| Feature | Description |
|
|
|---------|-------------|
|
|
| **AtomizerSpec v2.0** | Unified configuration format replacing `optimization_config.json` |
|
|
| **Spec REST API** | Full CRUD operations on spec via `/api/studies/{id}/spec` |
|
|
| **Custom Extractors** | Define custom Python functions as extractors in the spec |
|
|
| **WebSocket Sync** | Real-time spec synchronization between clients |
|
|
| **Legacy Migration** | Automatic migration of old `optimization_config.json` files |
|
|
|
|
### What's New in V3.0
|
|
|
|
| Feature | Description |
|
|
|---------|-------------|
|
|
| **File Browser** | Browse studies directory for .sim/.prt/.fem/.afem files |
|
|
| **Introspection Panel** | View discovered expressions, extractors, and dependencies |
|
|
| **One-Click Add** | Add expressions as design variables with a single click |
|
|
| **Claude Fixes** | Fixed SQL errors, WebSocket reconnection issues |
|
|
| **Health Check** | `/api/health` endpoint for database monitoring |
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Frontend Stack
|
|
|
|
| Component | Technology | Purpose |
|
|
|-----------|------------|---------|
|
|
| Flow Engine | React Flow | Node-based graph rendering |
|
|
| State Management | Zustand | Canvas state (nodes, edges, selection) |
|
|
| Icons | Lucide React | Professional icon library |
|
|
| Styling | Tailwind CSS | Dark theme (Atomaster palette) |
|
|
| Chat | WebSocket | Real-time Claude communication |
|
|
|
|
### Node Types (8)
|
|
|
|
| Node | Icon | Description | Color |
|
|
|------|------|-------------|-------|
|
|
| **Model** | `Cube` | NX model file (.prt, .sim, .fem) | Blue |
|
|
| **Solver** | `Cpu` | Nastran solution type (SOL101, SOL103, etc.) | Violet |
|
|
| **Design Variable** | `SlidersHorizontal` | Parameter to optimize with bounds | Emerald |
|
|
| **Extractor** | `FlaskConical` | Physics result extraction (E1-E10) | Cyan |
|
|
| **Objective** | `Target` | Optimization goal (minimize/maximize) | Rose |
|
|
| **Constraint** | `ShieldAlert` | Design constraint (upper/lower bounds) | Amber |
|
|
| **Algorithm** | `BrainCircuit` | Optimization method (TPE, CMA-ES, NSGA-II) | Indigo |
|
|
| **Surrogate** | `Rocket` | Neural acceleration (optional) | Pink |
|
|
|
|
### File Structure
|
|
|
|
```
|
|
atomizer-dashboard/frontend/src/
|
|
├── components/canvas/
|
|
│ ├── AtomizerCanvas.tsx # Main canvas component
|
|
│ ├── nodes/
|
|
│ │ ├── index.ts # Node type registry
|
|
│ │ ├── BaseNode.tsx # Base node with handles
|
|
│ │ ├── ModelNode.tsx # Model file node
|
|
│ │ ├── SolverNode.tsx # Solver type node
|
|
│ │ ├── DesignVarNode.tsx # Design variable node
|
|
│ │ ├── ExtractorNode.tsx # Extractor node
|
|
│ │ ├── ObjectiveNode.tsx # Objective node
|
|
│ │ ├── ConstraintNode.tsx # Constraint node
|
|
│ │ ├── AlgorithmNode.tsx # Algorithm node
|
|
│ │ ├── SurrogateNode.tsx # Surrogate node
|
|
│ │ └── CustomExtractorNode.tsx # Custom extractor node (V3.1)
|
|
│ ├── panels/
|
|
│ │ ├── NodeConfigPanel.tsx # Node configuration sidebar
|
|
│ │ ├── ValidationPanel.tsx # Validation toast display
|
|
│ │ ├── ExecuteDialog.tsx # Execute confirmation modal
|
|
│ │ ├── ChatPanel.tsx # Claude chat sidebar
|
|
│ │ ├── ConfigImporter.tsx # Study import dialog
|
|
│ │ ├── TemplateSelector.tsx # Workflow template chooser
|
|
│ │ ├── FileBrowser.tsx # File picker modal (V3)
|
|
│ │ ├── IntrospectionPanel.tsx # Model introspection results (V3)
|
|
│ │ ├── ExpressionSelector.tsx # Expression search dropdown (V3)
|
|
│ │ └── CustomExtractorPanel.tsx # Code editor for custom extractors (V3.1)
|
|
│ └── palette/
|
|
│ └── NodePalette.tsx # Draggable node palette
|
|
├── hooks/
|
|
│ ├── useCanvasStore.ts # Zustand store for canvas state
|
|
│ ├── useSpecStore.ts # Zustand store for AtomizerSpec (V3.1)
|
|
│ ├── useSpecSync.ts # WebSocket spec sync (V3.1)
|
|
│ └── useCanvasChat.ts # Claude chat integration
|
|
├── lib/
|
|
│ ├── canvas/
|
|
│ │ ├── schema.ts # TypeScript type definitions
|
|
│ │ ├── intent.ts # Intent serialization (legacy)
|
|
│ │ ├── validation.ts # Graph validation logic
|
|
│ │ └── templates.ts # Workflow templates
|
|
│ └── spec/
|
|
│ └── converter.ts # AtomizerSpec ↔ ReactFlow converter (V3.1)
|
|
├── types/
|
|
│ └── atomizer-spec.ts # AtomizerSpec TypeScript types (V3.1)
|
|
└── pages/
|
|
└── CanvasView.tsx # Canvas page (/canvas route)
|
|
```
|
|
|
|
### Backend File Structure (V3.1)
|
|
|
|
```
|
|
atomizer-dashboard/backend/api/
|
|
├── services/
|
|
│ ├── spec_manager.py # SpecManager - load/save/validate specs
|
|
│ ├── claude_agent.py # Claude API integration
|
|
│ └── context_builder.py # Context assembly with spec awareness
|
|
└── routes/
|
|
├── spec.py # AtomizerSpec REST API endpoints
|
|
└── optimization.py # Optimization endpoints
|
|
|
|
optimization_engine/
|
|
├── config/
|
|
│ ├── spec_models.py # Pydantic models for AtomizerSpec
|
|
│ ├── spec_validator.py # Semantic validation
|
|
│ └── migrator.py # Legacy config migration
|
|
├── extractors/
|
|
│ └── custom_extractor_loader.py # Runtime custom function loader
|
|
└── schemas/
|
|
└── atomizer_spec_v2.json # JSON Schema definition
|
|
```
|
|
|
|
---
|
|
|
|
## User Interface
|
|
|
|
### Layout
|
|
|
|
```
|
|
┌───────────────────────────────────────────────────────────────────┐
|
|
│ Canvas Builder Templates Import│
|
|
├──────────┬────────────────────────────────────────────┬───────────┤
|
|
│ │ │ │
|
|
│ Node │ Canvas Area │ Config │
|
|
│ Palette │ │ Panel │
|
|
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
|
|
│ [Model] │ │Model├──────│Solver├──────│Algo │ │ Label: │
|
|
│ [Solver]│ └─────┘ └──┬──┘ └─────┘ │ [____] │
|
|
│ [DVar] │ │ │ │
|
|
│ [Extr] │ ┌─────┐ ┌──┴──┐ ┌─────┐ │ Type: │
|
|
│ [Obj] │ │ DVar├──────│Extr ├──────│ Obj │ │ [____] │
|
|
│ [Const] │ └─────┘ └─────┘ └─────┘ │ │
|
|
│ [Algo] │ │ │
|
|
│ [Surr] │ │ │
|
|
│ │ │ │
|
|
├──────────┴────────────────────────────────────────────┴───────────┤
|
|
│ [Validate] [Process with Claude] │
|
|
└───────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Dark Theme (Atomaster Palette)
|
|
|
|
| Element | Color | Tailwind Class |
|
|
|---------|-------|----------------|
|
|
| Background | `#050A12` | `bg-dark-900` |
|
|
| Surface | `#0A1525` | `bg-dark-850` |
|
|
| Card | `#0F1E32` | `bg-dark-800` |
|
|
| Border | `#1A2F4A` | `border-dark-700` |
|
|
| Muted Text | `#5A7A9A` | `text-dark-400` |
|
|
| Primary | `#00D4E6` | `text-primary-400` |
|
|
|
|
---
|
|
|
|
## Core Workflows
|
|
|
|
### 1. Building a Workflow
|
|
|
|
1. **Drag nodes** from the left palette onto the canvas
|
|
2. **Connect nodes** by dragging from output handle to input handle
|
|
3. **Configure nodes** by clicking to open the config panel
|
|
4. **Validate** using the Validate button
|
|
5. **Process with Claude** to create the study
|
|
|
|
### 2. Importing from Existing Study
|
|
|
|
1. Click **Import** in the header
|
|
2. Select the **Load Study** tab
|
|
3. **Search** for your study by name
|
|
4. **Select** a study with an optimization_config.json
|
|
5. Click **Load Study** to populate the canvas
|
|
|
|
### 3. Using Templates
|
|
|
|
1. Click **Templates** in the header
|
|
2. Browse available workflow templates:
|
|
- **Mass Minimization**: Single-objective mass reduction
|
|
- **Multi-Objective**: Pareto optimization (mass + displacement)
|
|
- **Turbo Mode**: Neural-accelerated optimization
|
|
- **Mirror WFE**: Zernike wavefront error optimization
|
|
- **Frequency Target**: Natural frequency optimization
|
|
3. Click a template to load it
|
|
|
|
### 4. Processing with Claude
|
|
|
|
1. Build and configure your workflow
|
|
2. Click **Validate** to check for errors
|
|
3. Click **Process with Claude** to:
|
|
- Validate the configuration against Atomizer protocols
|
|
- Receive recommendations (method selection, trial count)
|
|
- Create the optimization study
|
|
|
|
---
|
|
|
|
## Node Configuration
|
|
|
|
### Model Node
|
|
|
|
| Field | Description | Example |
|
|
|-------|-------------|---------|
|
|
| File Path | Path to NX model | `models/bracket.sim` |
|
|
| File Type | prt, sim, or fem | `sim` |
|
|
|
|
When loading a `.sim` file, the system introspects to find:
|
|
- Linked `.prt` (geometry part)
|
|
- Linked `.fem` (FEM file)
|
|
- Solver type (SOL101, SOL103, etc.)
|
|
- Available expressions
|
|
|
|
### Design Variable Node
|
|
|
|
| Field | Description | Example |
|
|
|-------|-------------|---------|
|
|
| Expression Name | NX expression to vary | `thickness` |
|
|
| Min Value | Lower bound | `5.0` |
|
|
| Max Value | Upper bound | `15.0` |
|
|
| Unit | Engineering unit | `mm` |
|
|
|
|
**Expression Selector**: Click the dropdown to:
|
|
- **Search** through available expressions
|
|
- **Filter** by name
|
|
- **Refresh** to reload from model
|
|
- **Enter manually** if expression not found
|
|
|
|
### Extractor Node
|
|
|
|
| Field | Description | Options |
|
|
|-------|-------------|---------|
|
|
| Extractor ID | Protocol E1-E10 | E1 (Displacement), E2 (Frequency), etc. |
|
|
| Name | Display name | `max_displacement` |
|
|
| Config | Extractor-specific settings | Node ID, component, etc. |
|
|
|
|
**Available Extractors** (SYS_12):
|
|
|
|
| ID | Physics | Function |
|
|
|----|---------|----------|
|
|
| E1 | Displacement | `extract_displacement()` |
|
|
| E2 | Frequency | `extract_frequency()` |
|
|
| E3 | Stress | `extract_solid_stress()` |
|
|
| E4 | BDF Mass | `extract_mass_from_bdf()` |
|
|
| E5 | CAD Mass | `extract_mass_from_expression()` |
|
|
| E8 | Zernike | `extract_zernike_coefficients()` |
|
|
| E9 | Zernike | `extract_zernike_rms()` |
|
|
| E10 | Zernike | `extract_zernike_wfe()` |
|
|
|
|
### Objective Node
|
|
|
|
| Field | Description | Options |
|
|
|-------|-------------|---------|
|
|
| Name | Objective identifier | `mass`, `displacement` |
|
|
| Direction | Optimization goal | `minimize`, `maximize` |
|
|
| Weight | Multi-objective weight | `1.0` (0.0-10.0) |
|
|
|
|
### Constraint Node
|
|
|
|
| Field | Description | Example |
|
|
|-------|-------------|---------|
|
|
| Name | Constraint identifier | `max_stress` |
|
|
| Operator | Comparison type | `<=`, `>=`, `==` |
|
|
| Value | Threshold value | `250.0` |
|
|
|
|
### Algorithm Node
|
|
|
|
| Field | Description | Options |
|
|
|-------|-------------|---------|
|
|
| Method | Optimization algorithm | TPE, CMA-ES, NSGA-II, GP-BO |
|
|
| Max Trials | Number of trials | `100` |
|
|
| Timeout | Optional time limit | `3600` (seconds) |
|
|
|
|
**Method Selection** (SYS_15):
|
|
|
|
| Method | Best For | Design Vars | Objectives |
|
|
|--------|----------|-------------|------------|
|
|
| TPE | General purpose | 1-10 | 1 |
|
|
| CMA-ES | Many variables | 5-100 | 1 |
|
|
| NSGA-II | Multi-objective | 1-20 | 2-4 |
|
|
| GP-BO | Expensive evaluations | 1-10 | 1 |
|
|
|
|
### Surrogate Node
|
|
|
|
| Field | Description | Options |
|
|
|-------|-------------|---------|
|
|
| Enabled | Toggle acceleration | true/false |
|
|
| Model Type | Surrogate architecture | MLP, GNN, Auto |
|
|
| Min Trials | Trials before activation | `20` |
|
|
|
|
---
|
|
|
|
## Custom Extractors (V3.1)
|
|
|
|
Custom extractors allow you to define arbitrary Python extraction functions directly in the AtomizerSpec. These functions are validated for safety and executed during optimization.
|
|
|
|
### Creating a Custom Extractor
|
|
|
|
1. Add a **Custom Extractor** node from the palette
|
|
2. Open the **Code Editor** in the config panel
|
|
3. Write your extraction function following the required signature
|
|
4. The code is validated in real-time for:
|
|
- Correct function signature
|
|
- Allowed imports only (numpy, pyNastran)
|
|
- No dangerous operations (os.system, exec, eval, etc.)
|
|
|
|
### Function Signature
|
|
|
|
```python
|
|
def extract(op2_path, bdf_path=None, params=None, working_dir=None):
|
|
"""
|
|
Custom extraction function.
|
|
|
|
Args:
|
|
op2_path: Path to the .op2 results file
|
|
bdf_path: Path to the .bdf mesh file (optional)
|
|
params: Dict of current design variable values (optional)
|
|
working_dir: Path to the trial working directory (optional)
|
|
|
|
Returns:
|
|
Dict with output values, e.g., {"custom_metric": 42.0}
|
|
"""
|
|
import numpy as np
|
|
from pyNastran.op2.op2 import OP2
|
|
|
|
op2 = OP2()
|
|
op2.read_op2(op2_path)
|
|
|
|
# Your extraction logic here
|
|
result = np.max(op2.displacements[1].data)
|
|
|
|
return {"custom_metric": result}
|
|
```
|
|
|
|
### Allowed Imports
|
|
|
|
| Module | Usage |
|
|
|--------|-------|
|
|
| `numpy` | Numerical operations |
|
|
| `pyNastran` | OP2/BDF file parsing |
|
|
| `math` | Basic math functions |
|
|
| `pathlib` | Path manipulation |
|
|
|
|
### Security Restrictions
|
|
|
|
The following are **NOT allowed** in custom extractor code:
|
|
- `import os`, `import subprocess`, `import sys`
|
|
- `exec()`, `eval()`, `compile()`
|
|
- `__import__()`, `open()` with write mode
|
|
- Network operations
|
|
- File system modifications outside working_dir
|
|
|
|
### Example: Custom Stress Ratio Extractor
|
|
|
|
```python
|
|
def extract(op2_path, bdf_path=None, params=None, working_dir=None):
|
|
"""Extract stress ratio (max_stress / allowable)."""
|
|
import numpy as np
|
|
from pyNastran.op2.op2 import OP2
|
|
|
|
op2 = OP2()
|
|
op2.read_op2(op2_path)
|
|
|
|
# Get von Mises stress from solid elements
|
|
stress_data = op2.ctetra_stress[1].data
|
|
max_von_mises = np.max(stress_data[:, :, 7]) # Column 7 is von Mises
|
|
|
|
allowable = 250.0 # MPa
|
|
stress_ratio = max_von_mises / allowable
|
|
|
|
return {
|
|
"stress_ratio": stress_ratio,
|
|
"max_stress_mpa": max_von_mises
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## File Browser (V3)
|
|
|
|
The File Browser allows you to navigate the studies directory to select model files.
|
|
|
|
### Features
|
|
|
|
- **Directory Navigation**: Browse folder hierarchy with breadcrumbs
|
|
- **Type Filtering**: Filters to `.sim`, `.prt`, `.fem`, `.afem` by default
|
|
- **Search**: Quick search by file name
|
|
- **Single-Click Select**: Click a file to select and close
|
|
|
|
### Usage
|
|
|
|
1. Click the **Browse** button (folder icon) next to the Model file path input
|
|
2. Navigate to your study folder
|
|
3. Click a model file to select it
|
|
4. The path is automatically populated in the Model node
|
|
|
|
---
|
|
|
|
## Model Introspection (V3)
|
|
|
|
Model Introspection analyzes NX model files to discover expressions, solver type, and dependencies.
|
|
|
|
### Features
|
|
|
|
- **Expression Discovery**: Lists all expressions found in the model
|
|
- **Solver Detection**: Infers solver type from file contents (SOL101, SOL103, etc.)
|
|
- **Dependency Tracking**: Shows related .prt, .fem, .afem files
|
|
- **Extractor Suggestions**: Recommends extractors based on solver type
|
|
- **One-Click Add**: Add expressions as Design Variables instantly
|
|
|
|
### Usage
|
|
|
|
1. Configure a **Model** node with a valid file path
|
|
2. Click **Introspect Model** button
|
|
3. View discovered expressions, extractors, and files
|
|
4. Click **+** next to any expression to add as Design Variable
|
|
5. Click **+** next to any extractor to add to canvas
|
|
|
|
### Discovered Information
|
|
|
|
| Section | Contents |
|
|
|---------|----------|
|
|
| **Solver Type** | Detected solver (SOL101, SOL103, etc.) |
|
|
| **Expressions** | Name, current value, unit |
|
|
| **Extractors** | Available extractors for this solver |
|
|
| **Dependent Files** | Related .prt, .fem, .afem files |
|
|
|
|
---
|
|
|
|
## API Integration
|
|
|
|
### Backend Endpoints
|
|
|
|
#### AtomizerSpec REST API (V3.1)
|
|
|
|
The spec API provides full CRUD operations on the unified AtomizerSpec:
|
|
|
|
```
|
|
GET /api/studies/{study_id}/spec # Get full AtomizerSpec
|
|
Returns: AtomizerSpec JSON with meta, model, design_variables, extractors, objectives, constraints, optimization, canvas
|
|
|
|
PUT /api/studies/{study_id}/spec # Replace entire spec
|
|
Body: AtomizerSpec JSON
|
|
Returns: { hash: string, warnings: [] }
|
|
|
|
PATCH /api/studies/{study_id}/spec # Partial update (JSONPath)
|
|
Body: { path: "design_variables[0].bounds.max", value: 15.0, modified_by: "canvas" }
|
|
Returns: { hash: string }
|
|
|
|
POST /api/studies/{study_id}/spec/validate # Validate spec
|
|
Returns: { valid: boolean, errors: [], warnings: [] }
|
|
|
|
POST /api/studies/{study_id}/spec/nodes # Add node (design var, extractor, etc.)
|
|
Body: { type: "designVar", data: {...}, modified_by: "canvas" }
|
|
Returns: { node_id: "dv_002", hash: string }
|
|
|
|
PATCH /api/studies/{study_id}/spec/nodes/{id} # Update node
|
|
Body: { updates: {...}, modified_by: "canvas" }
|
|
Returns: { hash: string }
|
|
|
|
DELETE /api/studies/{study_id}/spec/nodes/{id} # Remove node
|
|
Query: modified_by=canvas
|
|
Returns: { hash: string }
|
|
|
|
POST /api/studies/{study_id}/spec/edges # Add edge connection
|
|
Query: source=ext_001&target=obj_001&modified_by=canvas
|
|
Returns: { hash: string }
|
|
```
|
|
|
|
#### Study Configuration
|
|
|
|
```
|
|
GET /api/studies/ # List all studies
|
|
GET /api/studies/{path}/config # Get optimization_config.json (legacy)
|
|
```
|
|
|
|
#### File Browser (V3)
|
|
|
|
```
|
|
GET /api/files/list # List files in directory
|
|
Query: path=subdir&types=.sim,.prt,.fem,.afem
|
|
Returns: { files: [{name, path, isDirectory}], path }
|
|
```
|
|
|
|
#### NX Introspection (V3)
|
|
|
|
```
|
|
POST /api/nx/introspect # Introspect NX model file
|
|
Body: { file_path: string }
|
|
Returns: {
|
|
file_path, file_type, expressions, solver_type,
|
|
dependent_files, extractors_available, warnings
|
|
}
|
|
|
|
GET /api/nx/expressions # Get expressions from model
|
|
Query: file_path=path/to/model.sim
|
|
Returns: { expressions: [{name, value, unit, type}] }
|
|
```
|
|
|
|
#### Health Check (V3)
|
|
|
|
```
|
|
GET /api/health # Check database and service health
|
|
Returns: { status: "healthy", database: "connected" }
|
|
```
|
|
|
|
### MCP Canvas Tools
|
|
|
|
The Canvas integrates with the MCP server for Claude tool use:
|
|
|
|
#### `validate_canvas_intent`
|
|
|
|
Validates an optimization intent from the Canvas.
|
|
|
|
```typescript
|
|
{
|
|
intent: OptimizationIntent // The canvas workflow as JSON
|
|
}
|
|
// Returns: { valid, errors, warnings, recommendations }
|
|
```
|
|
|
|
#### `execute_canvas_intent`
|
|
|
|
Creates an optimization study from a validated intent.
|
|
|
|
```typescript
|
|
{
|
|
intent: OptimizationIntent,
|
|
study_name: string, // snake_case name
|
|
auto_run?: boolean // Start optimization immediately
|
|
}
|
|
// Returns: { study_path, config_path, status }
|
|
```
|
|
|
|
#### `interpret_canvas_intent`
|
|
|
|
Analyzes a Canvas intent and provides recommendations.
|
|
|
|
```typescript
|
|
{
|
|
intent: OptimizationIntent
|
|
}
|
|
// Returns: {
|
|
// problem_type: "single-objective" | "multi-objective",
|
|
// complexity: "low" | "medium" | "high",
|
|
// recommended_method: string,
|
|
// recommended_trials: number,
|
|
// surrogate_recommended: boolean,
|
|
// notes: string[]
|
|
// }
|
|
```
|
|
|
|
---
|
|
|
|
## AtomizerSpec v2.0 Schema
|
|
|
|
The Canvas uses **AtomizerSpec v2.0** as the unified configuration format. This replaces the legacy `optimization_config.json` and `OptimizationIntent` with a single schema.
|
|
|
|
### Core Structure
|
|
|
|
```typescript
|
|
interface AtomizerSpec {
|
|
meta: {
|
|
version: "2.0";
|
|
created: string; // ISO timestamp
|
|
modified: string; // ISO timestamp
|
|
created_by: "canvas" | "claude" | "api" | "migration" | "manual";
|
|
modified_by: "canvas" | "claude" | "api" | "migration" | "manual";
|
|
study_name: string;
|
|
description?: string;
|
|
tags?: string[];
|
|
};
|
|
model: {
|
|
sim: { path: string; solver: string };
|
|
prt?: { path: string };
|
|
fem?: { path: string };
|
|
};
|
|
design_variables: DesignVariable[];
|
|
extractors: Extractor[];
|
|
objectives: Objective[];
|
|
constraints: Constraint[];
|
|
optimization: OptimizationConfig;
|
|
canvas: CanvasLayout;
|
|
}
|
|
```
|
|
|
|
### Design Variable
|
|
|
|
```typescript
|
|
interface DesignVariable {
|
|
id: string; // "dv_001", "dv_002", etc.
|
|
name: string; // Display name
|
|
expression_name: string; // NX expression name
|
|
type: "continuous" | "integer" | "categorical";
|
|
bounds: { min: number; max: number };
|
|
baseline?: number;
|
|
unit?: string;
|
|
enabled: boolean;
|
|
canvas_position: { x: number; y: number };
|
|
}
|
|
```
|
|
|
|
### Extractor
|
|
|
|
```typescript
|
|
interface Extractor {
|
|
id: string; // "ext_001", etc.
|
|
name: string; // Display name
|
|
type: string; // "mass", "displacement", "zernike_opd", "custom"
|
|
builtin: boolean; // true for E1-E10, false for custom
|
|
outputs: Array<{ name: string; units?: string }>;
|
|
config?: Record<string, unknown>;
|
|
custom_function?: { // For custom extractors only
|
|
code: string; // Python function code
|
|
entry_point: string; // Function name (default: "extract")
|
|
};
|
|
canvas_position: { x: number; y: number };
|
|
}
|
|
```
|
|
|
|
### Objective
|
|
|
|
```typescript
|
|
interface Objective {
|
|
id: string; // "obj_001", etc.
|
|
name: string; // Display name
|
|
direction: "minimize" | "maximize";
|
|
source: {
|
|
extractor_id: string; // Reference to extractor
|
|
output_name: string; // Which output from the extractor
|
|
};
|
|
weight?: number; // For weighted sum multi-objective
|
|
enabled: boolean;
|
|
canvas_position: { x: number; y: number };
|
|
}
|
|
```
|
|
|
|
### Canvas Layout
|
|
|
|
```typescript
|
|
interface CanvasLayout {
|
|
edges: Array<{ source: string; target: string }>;
|
|
layout_version: "2.0";
|
|
viewport?: { x: number; y: number; zoom: number };
|
|
}
|
|
```
|
|
|
|
### Example AtomizerSpec
|
|
|
|
```json
|
|
{
|
|
"meta": {
|
|
"version": "2.0",
|
|
"created": "2026-01-17T10:00:00Z",
|
|
"modified": "2026-01-17T10:30:00Z",
|
|
"created_by": "canvas",
|
|
"modified_by": "canvas",
|
|
"study_name": "bracket_mass_optimization",
|
|
"description": "Optimize bracket mass while maintaining stress limits"
|
|
},
|
|
"model": {
|
|
"sim": { "path": "bracket_sim1.sim", "solver": "nastran" }
|
|
},
|
|
"design_variables": [
|
|
{
|
|
"id": "dv_001",
|
|
"name": "Thickness",
|
|
"expression_name": "web_thickness",
|
|
"type": "continuous",
|
|
"bounds": { "min": 2.0, "max": 10.0 },
|
|
"baseline": 5.0,
|
|
"unit": "mm",
|
|
"enabled": true,
|
|
"canvas_position": { "x": 50, "y": 100 }
|
|
}
|
|
],
|
|
"extractors": [
|
|
{
|
|
"id": "ext_001",
|
|
"name": "Mass",
|
|
"type": "mass",
|
|
"builtin": true,
|
|
"outputs": [{ "name": "mass", "units": "kg" }],
|
|
"canvas_position": { "x": 740, "y": 100 }
|
|
}
|
|
],
|
|
"objectives": [
|
|
{
|
|
"id": "obj_001",
|
|
"name": "mass",
|
|
"direction": "minimize",
|
|
"source": { "extractor_id": "ext_001", "output_name": "mass" },
|
|
"enabled": true,
|
|
"canvas_position": { "x": 1020, "y": 100 }
|
|
}
|
|
],
|
|
"constraints": [],
|
|
"optimization": {
|
|
"algorithm": { "type": "TPE" },
|
|
"budget": { "max_trials": 100 }
|
|
},
|
|
"canvas": {
|
|
"edges": [
|
|
{ "source": "dv_001", "target": "model" },
|
|
{ "source": "model", "target": "solver" },
|
|
{ "source": "solver", "target": "ext_001" },
|
|
{ "source": "ext_001", "target": "obj_001" },
|
|
{ "source": "obj_001", "target": "optimization" }
|
|
],
|
|
"layout_version": "2.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Legacy OptimizationIntent (Deprecated)
|
|
|
|
The `OptimizationIntent` format is still supported for backwards compatibility but will be automatically converted to AtomizerSpec v2.0 when saved.
|
|
|
|
```typescript
|
|
interface OptimizationIntent {
|
|
model: {
|
|
path: string;
|
|
type: 'prt' | 'sim' | 'fem';
|
|
};
|
|
solver: {
|
|
type: string; // SOL101, SOL103, etc.
|
|
};
|
|
design_variables: Array<{
|
|
name: string;
|
|
expression: string;
|
|
min: number;
|
|
max: number;
|
|
unit?: string;
|
|
}>;
|
|
extractors: Array<{
|
|
id: string; // E1, E2, etc.
|
|
name: string;
|
|
config?: Record<string, unknown>;
|
|
}>;
|
|
objectives: Array<{
|
|
name: string;
|
|
extractor: string;
|
|
direction: 'minimize' | 'maximize';
|
|
weight?: number;
|
|
}>;
|
|
constraints?: Array<{
|
|
name: string;
|
|
extractor: string;
|
|
operator: '<=' | '>=' | '==';
|
|
value: number;
|
|
}>;
|
|
optimization: {
|
|
method: string;
|
|
max_trials: number;
|
|
timeout?: number;
|
|
};
|
|
surrogate?: {
|
|
enabled: boolean;
|
|
model_type?: string;
|
|
min_trials?: number;
|
|
};
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Validation Rules
|
|
|
|
The Canvas validates workflows against these rules:
|
|
|
|
### Required Components
|
|
|
|
- At least 1 **Model** node
|
|
- At least 1 **Solver** node
|
|
- At least 1 **Design Variable** node
|
|
- At least 1 **Objective** node
|
|
- At least 1 **Algorithm** node
|
|
|
|
### Configuration Rules
|
|
|
|
- All nodes must be **configured** (no empty fields)
|
|
- Design variable **min < max**
|
|
- Objective must connect to an **Extractor**
|
|
- Extractor ID must be valid (E1-E10)
|
|
|
|
### Connection Rules
|
|
|
|
- Model → Solver (required)
|
|
- Solver → Extractor (required for each extractor)
|
|
- Extractor → Objective (required for each objective)
|
|
- Extractor → Constraint (optional)
|
|
|
|
### Recommendations
|
|
|
|
- Multi-objective (2+ objectives) should use **NSGA-II**
|
|
- Many variables (5+) may benefit from **surrogate**
|
|
- High trial count (100+) should consider **neural acceleration**
|
|
|
|
---
|
|
|
|
## Templates
|
|
|
|
### Mass Minimization
|
|
|
|
Single-objective mass reduction with stress constraint.
|
|
|
|
- **Nodes**: 6 (Model, Solver, DVar, Extractor, Objective, Algorithm)
|
|
- **Objective**: Minimize mass
|
|
- **Constraint**: Max stress < limit
|
|
- **Method**: TPE (100 trials)
|
|
|
|
### Multi-Objective
|
|
|
|
Pareto optimization for mass vs. displacement trade-off.
|
|
|
|
- **Nodes**: 7
|
|
- **Objectives**: Minimize mass, Minimize displacement
|
|
- **Method**: NSGA-II (150 trials)
|
|
|
|
### Turbo Mode
|
|
|
|
Neural-accelerated optimization with surrogate.
|
|
|
|
- **Nodes**: 8 (includes Surrogate)
|
|
- **Objective**: User-defined
|
|
- **Method**: TPE + MLP Surrogate
|
|
- **Trials**: 50 FEA + 5000 surrogate
|
|
|
|
### Mirror WFE
|
|
|
|
Zernike wavefront error optimization for optics.
|
|
|
|
- **Nodes**: 7
|
|
- **Objective**: Minimize WFE (E10)
|
|
- **Method**: CMA-ES (200 trials)
|
|
|
|
### Frequency Target
|
|
|
|
Natural frequency optimization with modal analysis.
|
|
|
|
- **Nodes**: 6
|
|
- **Objective**: Target frequency (E2)
|
|
- **Method**: TPE (100 trials)
|
|
|
|
---
|
|
|
|
## Keyboard Shortcuts
|
|
|
|
| Key | Action |
|
|
|-----|--------|
|
|
| `Delete` / `Backspace` | Delete selected node |
|
|
| `Escape` | Deselect all |
|
|
| `Ctrl+Z` | Undo (future) |
|
|
| `Ctrl+Shift+Z` | Redo (future) |
|
|
| `Space` (hold) | Pan canvas |
|
|
| Scroll | Zoom in/out |
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Canvas Not Visible
|
|
|
|
- Ensure you're on the `/canvas` route
|
|
- Check for JavaScript errors in browser console
|
|
- Verify React Flow is properly initialized
|
|
|
|
### Nodes Not Draggable
|
|
|
|
- Check that drag-and-drop events are being captured
|
|
- Ensure `onDragStart` sets the correct data type
|
|
|
|
### Config Panel Not Updating
|
|
|
|
- Verify Zustand store is properly connected
|
|
- Check that `updateNodeData` is being called
|
|
|
|
### Claude Chat Not Working
|
|
|
|
- Check WebSocket connection status (green indicator)
|
|
- Verify backend is running on port 8000
|
|
- Check `/api/chat/` endpoint is accessible
|
|
|
|
### Expression Dropdown Empty
|
|
|
|
- Ensure a Model node is configured with a file path
|
|
- Check `/api/nx/expressions` endpoint is working
|
|
- Try the "Refresh" button to reload expressions
|
|
|
|
---
|
|
|
|
## Development
|
|
|
|
### Running Locally
|
|
|
|
```bash
|
|
# Frontend
|
|
cd atomizer-dashboard/frontend
|
|
npm install
|
|
npm run dev
|
|
|
|
# Backend
|
|
cd atomizer-dashboard/backend
|
|
python -m uvicorn api.main:app --reload --port 8000
|
|
|
|
# MCP Server
|
|
cd mcp-server/atomizer-tools
|
|
npm run build
|
|
npm run dev
|
|
```
|
|
|
|
### Building for Production
|
|
|
|
```bash
|
|
# Frontend
|
|
cd atomizer-dashboard/frontend
|
|
npm run build
|
|
|
|
# MCP Server
|
|
cd mcp-server/atomizer-tools
|
|
npm run build
|
|
```
|
|
|
|
### Adding New Node Types
|
|
|
|
1. Create node component in `components/canvas/nodes/`
|
|
2. Add type to `schema.ts`
|
|
3. Register in `nodes/index.ts`
|
|
4. Add to `NodePalette.tsx`
|
|
5. Update validation rules in `validation.ts`
|
|
6. Add serialization logic to `intent.ts`
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- **AtomizerSpec v2.0 Architecture**: See `docs/plans/UNIFIED_CONFIGURATION_ARCHITECTURE.md`
|
|
- **AtomizerSpec JSON Schema**: See `optimization_engine/schemas/atomizer_spec_v2.json`
|
|
- **React Flow Documentation**: https://reactflow.dev/
|
|
- **Lucide Icons**: https://lucide.dev/icons/
|
|
- **Zustand**: https://github.com/pmndrs/zustand
|
|
- **Atomizer Protocols**: See `docs/protocols/`
|
|
- **Extractor Library**: See `SYS_12_EXTRACTOR_LIBRARY.md`
|
|
- **Method Selector**: See `SYS_15_METHOD_SELECTOR.md`
|
|
|
|
---
|
|
|
|
*Canvas Builder: Design optimizations visually, execute with AI.*
|
|
*Powered by AtomizerSpec v2.0 - the unified configuration format.*
|