- Add DEVELOPMENT_ROADMAP.md with 7-phase plan for LLM-driven optimization
- Phase 1: Plugin system with lifecycle hooks
- Phase 2: Natural language configuration interface
- Phase 3: Dynamic code generation for custom objectives
- Phase 4: Intelligent analysis and decision support
- Phase 5: Automated HTML/PDF reporting
- Phase 6: NX MCP server integration
- Phase 7: Self-improving feature registry
- Update README.md to reflect LLM-native philosophy
- Emphasize natural language workflows
- Link to development roadmap
- Update architecture diagrams
- Add future capability examples
- Reorganize documentation structure
- Move old dev docs to docs/archive/
- Clean up root directory
- Preserve all working optimization engine code
This sets the foundation for transforming Atomizer into an AI-powered
engineering assistant that can autonomously configure optimizations,
generate custom analysis code, and provide intelligent recommendations.
Round design variables, objectives, and constraints to appropriate
decimal precision based on physical units (4 decimals for mm, degrees, MPa).
- Added _get_precision() method with unit-based precision mapping
- Round design variables when sampled from Optuna
- Round extracted results (objectives and constraints)
- Added units field to objectives in config files
- Tested: values now show 4 decimals instead of 17+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Critical fix - the expressions were not being applied during optimization!
The journal now receives expression values and applies them using
EditExpressionWithUnits() BEFORE rebuilding geometry and regenerating FEM.
## Key Changes
### Expression Application in Journal (solve_simulation.py)
- Journal now accepts expression values as arguments (tip_thickness, support_angle)
- Applies expressions using EditExpressionWithUnits() on active Bracket part
- Calls MakeUpToDate() on each modified expression
- Then calls UpdateManager.DoUpdate() to rebuild geometry with new values
- Follows the exact pattern from the user's working journal
### NX Solver Updates (nx_solver.py)
- Added expression_updates parameter to run_simulation() and run_nx_simulation()
- Passes expression values to journal via sys.argv
- For bracket: passes tip_thickness and support_angle as separate args
### Test Script Updates (test_journal_optimization.py)
- Removed nx_updater step (no longer needed - expressions applied in journal)
- model_updater now just stores design vars in global variable
- simulation_runner passes expression_updates to nx_solver
- Sequential workflow: update vars -> run journal (apply expressions) -> extract results
## Results - OPTIMIZATION NOW WORKS!
Before (all trials same stress):
- Trial 0: tip=23.48, angle=37.21 → stress=197.89 MPa
- Trial 1: tip=20.08, angle=20.32 → stress=197.89 MPa (SAME!)
- Trial 2: tip=18.19, angle=35.23 → stress=197.89 MPa (SAME!)
After (varying stress values):
- Trial 0: tip=21.62, angle=30.15 → stress=192.71 MPa ✅
- Trial 1: tip=17.17, angle=33.52 → stress=167.96 MPa ✅ BEST!
- Trial 2: tip=15.06, angle=21.81 → stress=242.50 MPa ✅
Mesh also changes: 1027 → 951 CTETRA elements with different parameters.
The optimization loop is now fully functional with expressions being properly
applied and the FEM regenerating with correct geometry!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit completes the optimization loop infrastructure by implementing
the full FEM regeneration workflow based on the user's working journal.
## Changes
### FEM Regeneration Workflow (solve_simulation.py)
- Added STEP 1: Switch to Bracket.prt and update geometry
- Uses SetActiveDisplay() to make Bracket.prt active
- Calls UpdateManager.DoUpdate() to rebuild CAD geometry with new expressions
- Added STEP 2: Switch to Bracket_fem1 and update FE model
- Uses SetActiveDisplay() to make FEM active
- Calls fEModel1.UpdateFemodel() to regenerate FEM with updated geometry
- Added STEP 3: Switch back to sim part before solving
- Close and reopen .sim file to force reload from disk
### Enhanced Journal Output (nx_solver.py)
- Display journal stdout output for debugging
- Shows all journal steps: geometry update, FEM regeneration, solve, save
- Helps verify workflow execution
### Verification Tools
- Added verify_parametric_link.py journal to check expression dependencies
- Added FEM_REGENERATION_STATUS.md documenting the complete status
## Status
### ✅ Fully Functional Components
1. Parameter updates - nx_updater.py modifies .prt expressions
2. NX solver - ~4s per solve via journal
3. Result extraction - pyNastran reads .op2 files
4. History tracking - saves to JSON/CSV
5. Optimization loop - Optuna explores parameter space
6. **FEM regeneration workflow** - Journal executes all steps successfully
### ❌ Remaining Issue: Expressions Not Linked to Geometry
The optimization returns identical stress values (197.89 MPa) for all trials
because the Bracket.prt expressions are not referenced by any geometry features.
Evidence:
- Journal verification shows FEM update steps execute successfully
- Feature dependency check shows no features reference the expressions
- All optimization infrastructure is working correctly
The code is ready - waiting for Bracket.prt to have its expressions properly
linked to the geometry features in NX.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Integrate OP2 data extraction with optimization config builder:
- Add build_optimization_config() MCP tool
- Add list_optimization_options() helper
- Add format_optimization_options_for_llm() formatter
- Update MCP tools documentation with full API details
- Test with bracket example, generates valid config
Features:
- Discovers design variables from FEA model
- Lists 4 available objectives (mass, stress, displacement, volume)
- Lists 4 available constraints (stress/displacement/mass limits)
- Validates user selections against model
- Generates complete optimization_config.json
Tested with examples/bracket/Bracket_sim1.sim:
- Found 4 design variables (support_angle, tip_thickness, p3, support_blend_radius)
- Created config with 2 objectives, 2 constraints, 150 trials
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added complete working example with all NX result files for testing
and validation of the OP2 result extractor.
Files Added (examples/bracket/):
- Bracket.prt: Part geometry with expressions
- Bracket_sim1.sim: Simulation definition (SOL 101 Linear Statics)
- Bracket_fem1.fem: Finite element mesh
- bracket_sim1-solution_1.op2: Binary results (666 KB)
- bracket_sim1-solution_1.f06: ASCII results log
- bracket_sim1-solution_1.dat: Nastran input deck
- Supporting files: .diag, .f04, .log, .html, .png
Validated Results from OP2:
✓ Max Displacement: 0.362 mm (node 91)
- Primary direction: -Z (-0.354 mm)
- Load application point
✓ Max von Mises Stress: 122.91 MPa (element 79, CHEXA)
- Material: Aluminum 6061-T6 (yield = 276 MPa)
- Safety Factor: 2.25 ✅ SAFE
- Well below yield strength
Units Handling:
- NX units: mm, mN (milli-newton), kg
- Stress in OP2: mN/mm² = kPa
- Conversion required: kPa / 1000 = MPa
- Displacement: mm (direct)
Model Properties:
- Analysis Type: SOL 101 Linear Statics
- Elements: 585 (CHEXA hexahedral)
- Load: ~1000 N in -Z direction (3 application points)
- Constraints: Fixed supports at base
- Material: Al 6061-T6
Optimization Potential:
Current design has good margins:
- Displacement: 0.36 mm (could allow up to ~1.0 mm)
- Stress: 122.91 MPa (could allow up to ~200 MPa)
→ Weight reduction opportunity while maintaining safety!
This validates:
- pyNastran OP2 extraction works correctly
- Units conversion handling (mN → N, kPa → MPa)
- Multi-objective optimization is feasible
- Example ready for testing optimization workflow