Files
Atomizer/docs/06_PROTOCOLS_DETAILED/ASSEMBLY_FEM_WORKFLOW.md
Antoine ec5e42d733 feat: Add M1 mirror Zernike optimization with correct RMS calculation
Major improvements to telescope mirror optimization workflow:

Assembly FEM Workflow (solve_simulation.py):
- Fixed multi-part assembly FEM update sequence
- Use ImportFromFile() for reliable expression updates
- Add DuplicateNodesCheckBuilder with MergeOccurrenceNodes=True
- Switch to Foreground solve mode for multi-subcase solutions
- Add detailed logging and diagnostics for node merge operations

Zernike RMS Calculation:
- CRITICAL FIX: Use correct surface-based RMS formula
  - Global RMS = sqrt(mean(W^2)) from actual WFE values
  - Filtered RMS = sqrt(mean(W_residual^2)) after removing low-order fit
  - This matches zernike_Post_Script_NX.py (optical standard)
- Previous WRONG formula was: sqrt(sum(coeffs^2))
- Add compute_rms_filter_j1to3() for optician workload metric

Subcase Mapping:
- Fix subcase mapping to match NX model:
  - Subcase 1 = 90 deg (polishing orientation)
  - Subcase 2 = 20 deg (reference)
  - Subcase 3 = 40 deg
  - Subcase 4 = 60 deg

New Study: M1 Mirror Zernike Optimization
- Full optimization config with 11 design variables
- 3 objectives: rel_filtered_rms_40_vs_20, rel_filtered_rms_60_vs_20, mfg_90_optician_workload
- Neural surrogate support for accelerated optimization

Documentation:
- Update ZERNIKE_INTEGRATION.md with correct RMS formula
- Update ASSEMBLY_FEM_WORKFLOW.md with expression import and node merge details
- Add reference scripts from original zernike_Post_Script_NX.py

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 16:30:15 -05:00

6.2 KiB

Assembly FEM Optimization Workflow

This document describes the multi-part assembly FEM workflow used when optimizing complex assemblies with .afm (Assembly FEM) files.

Overview

Assembly FEMs have a more complex dependency chain than single-part simulations:

.prt (geometry) → _fem1.fem (component mesh) → .afm (assembly mesh) → .sim (solution)

Each level must be updated in sequence when design parameters change.

When This Workflow Applies

This workflow is automatically triggered when:

  • The working directory contains .afm files
  • Multiple .fem files exist (component meshes)
  • Multiple .prt files exist (component geometry)

Examples:

  • M1 Mirror assembly (M1_Blank + M1_Vertical_Support_Skeleton)
  • Multi-component mechanical assemblies
  • Any NX assembly where components have separate FEM files

The 4-Step Workflow

Step 1: Update Expressions in Geometry Part (.prt)

Open M1_Blank.prt
├── Find and update design expressions
│   ├── whiffle_min = 42.5
│   ├── whiffle_outer_to_vertical = 75.0
│   └── inner_circular_rib_dia = 550.0
├── Rebuild geometry (DoUpdate)
└── Save part

The .prt file contains the parametric CAD model with expressions that drive dimensions. These expressions are updated with new design parameter values, then the geometry is rebuilt.

Step 2: Update Component FEM Files (.fem)

For each component FEM:
├── Open M1_Blank_fem1.fem
│   ├── UpdateFemodel() - regenerates mesh from updated geometry
│   └── Save FEM
├── Open M1_Vertical_Support_Skeleton_fem1.fem
│   ├── UpdateFemodel()
│   └── Save FEM
└── ... (repeat for all component FEMs)

Each component FEM is linked to its source geometry. UpdateFemodel() regenerates the mesh based on the updated geometry.

Step 3: Update Assembly FEM (.afm)

Open ASSY_M1_assyfem1.afm
├── UpdateFemodel() - updates assembly mesh
├── Merge coincident nodes (at component interfaces)
├── Resolve labeling conflicts (duplicate node/element IDs)
└── Save AFM

The assembly FEM combines component meshes. This step:

  • Reconnects meshes at shared interfaces
  • Resolves numbering conflicts between component meshes
  • Ensures mesh continuity for accurate analysis

Step 4: Solve Simulation (.sim)

Open ASSY_M1_assyfem1_sim1.sim
├── Execute solve
│   ├── Foreground mode for all solutions
│   └── or Background mode for specific solution
└── Save simulation

The simulation file references the assembly FEM and contains solution setup (loads, constraints, subcases).

File Dependencies

M1 Mirror Example:

M1_Blank.prt ─────────────────────> M1_Blank_fem1.fem ─────────┐
     │                                    │                    │
     │ (expressions)                      │ (component mesh)   │
     ↓                                    ↓                    │
M1_Vertical_Support_Skeleton.prt ──> M1_..._Skeleton_fem1.fem ─┤
                                                               │
                                                               ↓
                                          ASSY_M1_assyfem1.afm ──> ASSY_M1_assyfem1_sim1.sim
                                               (assembly mesh)         (solution)

API Functions Used

Step NX API Call Purpose
1 OpenBase() Open .prt file
1 ImportFromFile() Import expressions from .exp file (preferred)
1 DoUpdate() Rebuild geometry
2-3 UpdateFemodel() Regenerate mesh from geometry
3 DuplicateNodesCheckBuilder Merge coincident nodes at interfaces
3 MergeOccurrenceNodes = True Critical: enables cross-component merge
4 SolveAllSolutions() Execute FEA (Foreground mode recommended)

Expression Update Method

The recommended approach uses expression file import:

# Write expressions to .exp file
with open(exp_path, 'w') as f:
    for name, value in expressions.items():
        unit = get_unit_for_expression(name)
        f.write(f"[{unit}]{name}={value}\n")

# Import into part
modified, errors = workPart.Expressions.ImportFromFile(
    exp_path,
    NXOpen.ExpressionCollection.ImportMode.Replace
)

This is more reliable than EditExpressionWithUnits() for batch updates.

Error Handling

Common issues and solutions:

"Update undo happened"

  • Geometry update failed due to constraint violations
  • Check expression values are within valid ranges
  • May need to adjust parameter bounds

"This operation can only be done on the work part"

  • Work part not properly set before operation
  • Use SetWork() to make target part the work part

Node merge warnings

  • Manual intervention may be needed for complex interfaces
  • Check mesh connectivity in NX after solve

"Billion nm" RMS values

  • Indicates node merging failed - coincident nodes not properly merged
  • Check MergeOccurrenceNodes = True is set
  • Verify tolerance (0.01 mm recommended)
  • Run node merge after every FEM update, not just once

Configuration

The workflow auto-detects assembly FEMs, but you can configure behavior:

{
  "nx_settings": {
    "expression_part": "M1_Blank",  // Override auto-detection
    "component_fems": [              // Explicit list of FEMs to update
      "M1_Blank_fem1.fem",
      "M1_Vertical_Support_Skeleton_fem1.fem"
    ],
    "afm_file": "ASSY_M1_assyfem1.afm"
  }
}

Implementation Reference

See optimization_engine/solve_simulation.py for the full implementation:

  • detect_assembly_fem() - Detects if assembly workflow needed
  • update_expressions_in_part() - Step 1 implementation
  • update_fem_part() - Step 2 implementation
  • update_assembly_fem() - Step 3 implementation
  • solve_simulation_file() - Step 4 implementation

Tips

  1. Start with baseline solve: Before optimization, manually verify the full workflow completes in NX
  2. Check mesh quality: Poor mesh quality after updates can cause solve failures
  3. Monitor memory: Assembly FEMs with many components use significant memory
  4. Use Foreground mode: For multi-subcase solutions, Foreground mode ensures all subcases complete