fix: generic mass extraction in solve_simulation.py (beam + bracket)

- Extract mass RIGHT AFTER geometry rebuild while part is work part
- Replace unreliable p173 expression lookup with MeasureManager
- Skip re-extraction if mass already captured during rebuild
- Relax displacement constraint to 20mm (DEC-HB-012, CEO approved)

Root cause: journal hardcoded M1_Blank for bracket, failed silently on Beam.prt
Fix by: NX Expert + Manager diagnosis
This commit is contained in:
2026-02-13 02:16:39 +00:00
parent 57130ccfbc
commit 580ed65a26
3 changed files with 31 additions and 18 deletions

View File

@@ -1013,6 +1013,15 @@ def solve_simple_workflow(
theSession.DeleteUndoMark(markId_update, "NX update") theSession.DeleteUndoMark(markId_update, "NX update")
print(f"[JOURNAL] Geometry rebuilt ({nErrs} errors)") print(f"[JOURNAL] Geometry rebuilt ({nErrs} errors)")
# Extract mass NOW while geometry part is work part and freshly rebuilt
# This is the most reliable timing — solid bodies reflect updated parameters
print(f"[JOURNAL] Extracting mass from {workPart.Name}...")
try:
mass_kg = extract_part_mass(theSession, workPart, working_dir)
print(f"[JOURNAL] Mass extracted: {mass_kg:.6f} kg")
except Exception as mass_err:
print(f"[JOURNAL] WARNING: Mass extraction after rebuild failed: {mass_err}")
# Save geometry part # Save geometry part
print(f"[JOURNAL] Saving geometry part...") print(f"[JOURNAL] Saving geometry part...")
partSaveStatus_geom = workPart.Save( partSaveStatus_geom = workPart.Save(
@@ -1171,25 +1180,22 @@ def solve_simple_workflow(
) )
# Extract mass and write to _temp_mass.txt # Extract mass and write to _temp_mass.txt
# Strategy: try expression lookup first, fall back to MeasureManager # Strategy: Use MeasureManager on geometry part (most reliable)
# Note: Mass may have already been extracted during geometry rebuild phase above.
# This post-solve extraction ensures we have mass even if no expression updates were done.
try: try:
mass_value = None mass_value = None
# Attempt 1: Read mass from expression p173 on geometry part # Check if mass was already written during geometry rebuild
try: mass_file = os.path.join(working_dir, "_temp_mass.txt")
for part in theSession.Parts: if os.path.exists(mass_file) and expression_updates:
part_type = type(part).__name__ print(f"[JOURNAL] Mass already extracted during geometry rebuild phase")
if "fem" not in part_type.lower() and "sim" not in part_type.lower(): with open(mass_file, "r") as f:
for expr in part.Expressions: content = f.read().strip()
if expr.Name == "p173": print(f"[JOURNAL] Existing mass file: {content}")
mass_value = expr.Value mass_value = -1 # sentinel to skip re-extraction
print(f"[JOURNAL] Mass expression p173 = {mass_value}")
break
break
except Exception as expr_err:
print(f"[JOURNAL] Expression lookup failed: {expr_err}")
# Attempt 2: Use MeasureManager (more reliable for derived/measurement expressions) # Use MeasureManager if mass not yet extracted
if mass_value is None: if mass_value is None:
print(f"[JOURNAL] Expression p173 not found, using MeasureManager fallback...") print(f"[JOURNAL] Expression p173 not found, using MeasureManager fallback...")
geom_part = None geom_part = None
@@ -1206,12 +1212,12 @@ def solve_simple_workflow(
print(f"[JOURNAL] MeasureManager failed: {mm_err}") print(f"[JOURNAL] MeasureManager failed: {mm_err}")
# Write mass file (extract_part_mass may have already written it, but ensure consistency) # Write mass file (extract_part_mass may have already written it, but ensure consistency)
if mass_value is not None: if mass_value is not None and mass_value != -1:
mass_file = os.path.join(working_dir, "_temp_mass.txt") mass_file = os.path.join(working_dir, "_temp_mass.txt")
with open(mass_file, "w") as f: with open(mass_file, "w") as f:
f.write(f"p173={mass_value}\n") f.write(f"p173={mass_value}\n")
print(f"[JOURNAL] Wrote mass to {mass_file}") print(f"[JOURNAL] Wrote mass to {mass_file}")
else: elif mass_value is None:
print(f"[JOURNAL] WARNING: Could not extract mass via expression or MeasureManager") print(f"[JOURNAL] WARNING: Could not extract mass via expression or MeasureManager")
except Exception as e: except Exception as e:
print(f"[JOURNAL] WARNING: Mass extraction failed: {e}") print(f"[JOURNAL] WARNING: Mass extraction failed: {e}")

View File

@@ -20,7 +20,7 @@ Minimize beam mass while meeting displacement and stress constraints. Single-obj
| hole_span | `p6` (→ `Pattern_p9`) | 4,000 | TBD | mm | Potential (G15) | Total span for hole distribution | | hole_span | `p6` (→ `Pattern_p9`) | 4,000 | TBD | mm | Potential (G15) | Total span for hole distribution |
## Constraints ## Constraints
- Max tip displacement: ≤ 10 mm - Max tip displacement: ≤ 20 mm (relaxed from 10mm — CEO approved 2026-02-13, dummy case)
- Max von Mises stress: ≤ ~130 MPa (steel, conservative — Gap G9) - Max von Mises stress: ≤ ~130 MPa (steel, conservative — Gap G9)
- Mass tracked via NX expression **`p173`** (`body_property147.mass` [kg]) - Mass tracked via NX expression **`p173`** (`body_property147.mass` [kg])

View File

@@ -79,6 +79,13 @@ Numbered decision log. Check here before proposing anything that contradicts a p
- **Rationale:** Optuna DB is study-scoped and can be cleaned/reset. History DB provides permanent record across studies, enabling cross-study learning, debugging, and auditability. Append-only means no data loss. - **Rationale:** Optuna DB is study-scoped and can be cleaned/reset. History DB provides permanent record across studies, enabling cross-study learning, debugging, and auditability. Append-only means no data loss.
- **Status:** Approved — implemented and tested - **Status:** Approved — implemented and tested
## DEC-HB-012: Relax displacement constraint to 20mm
- **Date:** 2026-02-13
- **By:** CEO
- **Decision:** Relax max tip displacement constraint from 10 mm to 20 mm. Stress constraint unchanged (≤ 130 MPa).
- **Rationale:** Hydrotech Beam is a dummy/proving case — goal is to validate the full optimization pipeline end-to-end, not achieve a real engineering target. 10mm was unreachable in the current design space (baseline 19.6mm, 0/51 DOE trials feasible). 20mm makes feasibility achievable.
- **Status:** Approved
## DEC-HB-011: Git-only development workflow (Syncthing paused) ## DEC-HB-011: Git-only development workflow (Syncthing paused)
- **Date:** 2026-02-11 - **Date:** 2026-02-11
- **By:** CEO - **By:** CEO