Files
Atomizer/docs/NX_MULTI_SOLUTION_PROTOCOL.md
Anto01 74a92803b7 feat: Add automatic solution monitor disabling for multi-solution workflows
Problem:
When running optimization studies with multiple solutions (e.g., static + modal),
NX opens solution monitor windows for each trial. These windows superpose and cause
usability issues during long optimization runs.

Solution:
- Automatically disable solution monitor when solving all solutions (solution_name=None)
- Loop through all solutions and set "solution monitor" property to False
- Implemented in solve_simulation.py before solve execution (lines 271-295)
- Includes error handling with graceful fallback

Benefits:
- No monitor window pile-up during optimization studies
- Better performance (no GUI overhead)
- No user configuration required - works automatically
- Based on user-recorded journal (journal_monitor_window_off.py)

Documentation:
- Updated docs/NX_MULTI_SOLUTION_PROTOCOL.md with solution monitor control section
- Added implementation details and when the feature activates
- Cross-referenced user's recorded journal

Implementation: optimization_engine/solve_simulation.py
Documentation: docs/NX_MULTI_SOLUTION_PROTOCOL.md
Reference: nx_journals/user_generated_journals/journal_monitor_window_off.py
2025-11-24 10:36:10 -05:00

8.6 KiB

NX Multi-Solution Solve Protocol

Critical Finding: SolveAllSolutions API Required for Multi-Solution Models

Date: November 23, 2025 Last Updated: November 23, 2025 Protocol: Multi-Solution Nastran Solve Affected Models: Any NX simulation with multiple solutions (e.g., static + modal, thermal + structural)


Problem Statement

When an NX simulation contains multiple solutions (e.g., Solution 1 = Static Analysis, Solution 2 = Modal Analysis), using SolveChainOfSolutions() with Background mode does not wait for all solutions to complete before returning control to Python. This causes:

  1. Missing OP2 Files: Only the first solution's OP2 file is generated
  2. Stale Data: Subsequent trials read old OP2 files from previous runs
  3. Identical Results: All trials show the same values for results from missing solutions
  4. Silent Failures: No error is raised - the solve completes but files are not written

Example Scenario

Drone Gimbal Arm Optimization:

  • Solution 1: Static analysis (stress, displacement)
  • Solution 2: Modal analysis (frequency)

Symptoms:

  • All 100 trials showed identical frequency (27.476 Hz)
  • Only beam_sim1-solution_1.op2 was created
  • beam_sim1-solution_2.op2 was never regenerated after Trial 0
  • Both .dat files were written correctly, but solve didn't wait for completion

Root Cause

# WRONG APPROACH (doesn't wait for completion)
psolutions1 = []
solution_idx = 1
while True:
    solution_obj_name = f"Solution[Solution {solution_idx}]"
    simSolution = simSimulation1.FindObject(solution_obj_name)
    if simSolution:
        psolutions1.append(simSolution)
        solution_idx += 1
    else:
        break

theCAESimSolveManager.SolveChainOfSolutions(
    psolutions1,
    NXOpen.CAE.SimSolution.SolveOption.Solve,
    NXOpen.CAE.SimSolution.SetupCheckOption.CompleteDeepCheckAndOutputErrors,
    NXOpen.CAE.SimSolution.SolveMode.Background  # ❌ Returns immediately!
)

Issue: Background mode runs asynchronously and returns control to Python before all solutions finish solving.


Correct Solution

For Solving All Solutions

Use SolveAllSolutions() API with Foreground mode:

# CORRECT APPROACH (waits for completion)
if solution_name:
    # Solve specific solution in background mode
    solution_obj_name = f"Solution[{solution_name}]"
    simSolution1 = simSimulation1.FindObject(solution_obj_name)
    psolutions1 = [simSolution1]

    numsolutionssolved1, numsolutionsfailed1, numsolutionsskipped1 = theCAESimSolveManager.SolveChainOfSolutions(
        psolutions1,
        NXOpen.CAE.SimSolution.SolveOption.Solve,
        NXOpen.CAE.SimSolution.SetupCheckOption.CompleteDeepCheckAndOutputErrors,
        NXOpen.CAE.SimSolution.SolveMode.Background
    )
else:
    # Solve ALL solutions using SolveAllSolutions API (Foreground mode)
    # This ensures all solutions (static + modal, etc.) complete before returning
    print(f"[JOURNAL] Solving all solutions using SolveAllSolutions API (Foreground mode)...")

    numsolutionssolved1, numsolutionsfailed1, numsolutionsskipped1 = theCAESimSolveManager.SolveAllSolutions(
        NXOpen.CAE.SimSolution.SolveOption.Solve,
        NXOpen.CAE.SimSolution.SetupCheckOption.CompleteCheckAndOutputErrors,
        NXOpen.CAE.SimSolution.SolveMode.Foreground,  # ✅ Blocks until complete
        False
    )

Key Differences

Aspect SolveChainOfSolutions SolveAllSolutions
Manual enumeration Required (loop through solutions) Automatic (handles all solutions)
Background mode behavior Returns immediately, async N/A (Foreground recommended)
Foreground mode behavior Blocks until complete Blocks until complete
Use case Specific solution selection Solve all solutions

Implementation Location

File: optimization_engine/solve_simulation.py Lines: 271-295

When to use this protocol:

  • When solution_name=None is passed to NXSolver.run_simulation()
  • Any simulation with multiple solutions that must all complete
  • Multi-objective optimization requiring results from different analysis types

Verification Steps

After implementing the fix, verify:

  1. Both .dat files are written (one per solution)

    beam_sim1-solution_1.dat  # Static analysis
    beam_sim1-solution_2.dat  # Modal analysis
    
  2. Both .op2 files are created with updated timestamps

    beam_sim1-solution_1.op2  # Contains stress, displacement
    beam_sim1-solution_2.op2  # Contains eigenvalues, mode shapes
    
  3. Results are unique per trial - check that frequency values vary across trials

  4. Journal log shows:

    [JOURNAL] Solving all solutions using SolveAllSolutions API (Foreground mode)...
    [JOURNAL] Solve completed!
    [JOURNAL]   Solutions solved: 2
    

Solution Monitor Window Control (November 24, 2025)

Problem: Monitor Window Pile-Up

When running optimization studies with multiple trials, NX opens solution monitor windows for each trial. These windows:

  • Superpose on top of each other
  • Cannot be easily closed programmatically
  • Cause usability issues during long optimization runs
  • Slow down the optimization process

Solution: Automatic Monitor Disabling

The solution monitor is now automatically disabled when solving multiple solutions (when solution_name=None).

Implementation: optimization_engine/solve_simulation.py lines 271-295

# CRITICAL: Disable solution monitor when solving multiple solutions
# This prevents NX from opening multiple monitor windows which superpose and cause usability issues
if not solution_name:
    print("[JOURNAL] Disabling solution monitor for all solutions to prevent window pile-up...")
    try:
        # Get all solutions in the simulation
        solutions_disabled = 0
        solution_num = 1
        while True:
            try:
                solution_obj_name = f"Solution[Solution {solution_num}]"
                simSolution = simSimulation1.FindObject(solution_obj_name)
                if simSolution:
                    propertyTable = simSolution.SolverOptionsPropertyTable
                    propertyTable.SetBooleanPropertyValue("solution monitor", False)
                    solutions_disabled += 1
                    solution_num += 1
                else:
                    break
            except:
                break  # No more solutions
        print(f"[JOURNAL]   Solution monitor disabled for {solutions_disabled} solution(s)")
    except Exception as e:
        print(f"[JOURNAL]   WARNING: Could not disable solution monitor: {e}")
        print(f"[JOURNAL]   Continuing with solve anyway...")

When this activates:

  • Automatically when solution_name=None (solve all solutions mode)
  • For any study with multiple trials (typical optimization scenario)
  • No user configuration required

User-recorded journal: nx_journals/user_generated_journals/journal_monitor_window_off.py


  1. All trials showing identical frequency: Fixed by ensuring modal solution runs
  2. Only one data point in dashboard: Fixed by all trials succeeding
  3. Parallel coordinates with NaN: Fixed by having complete data from all solutions
  4. Solution monitor windows piling up: Fixed by automatically disabling monitor for multi-solution runs

References

  • User's Example: nx_journals/user_generated_journals/journal_solve_all_solution.py (line 27)
  • NX Open Documentation: SimSolveManager.SolveAllSolutions() method
  • Implementation: optimization_engine/solve_simulation.py

Best Practices

  1. Always use Foreground mode when solving all solutions
  2. Verify OP2 timestamp changes to ensure fresh solves
  3. Check solve counts in journal output to confirm both solutions ran
  4. Test with 5 trials before running large optimizations
  5. Monitor unique frequency values as a smoke test for multi-solution models

Example Use Cases

Correct Usage

# Multi-objective optimization with static + modal
result = nx_solver.run_simulation(
    sim_file=sim_file,
    working_dir=model_dir,
    expression_updates=design_vars,
    solution_name=None  # Solve ALL solutions
)

Incorrect Usage (Don't Do This)

# Running modal separately - inefficient and error-prone
result1 = nx_solver.run_simulation(..., solution_name="Solution 1")  # Static
result2 = nx_solver.run_simulation(..., solution_name="Solution 2")  # Modal
# This doubles the solve time and requires managing two result objects

Status: Implemented and Verified Impact: Critical for all multi-solution optimization workflows