Files
Atomizer/examples/debug_op2_stress.py
Anto01 723b71e60b fix: Complete stress extraction fix for NX Nastran OP2 files
THREE critical fixes applied:

1. API Access Pattern
   - Support dotted attribute names (e.g., 'stress.chexa_stress')
   - Compatible with newer pyNastran versions (NX 2412.5)
   - Fallback to older API formats for compatibility

2. Correct Von Mises Index
   - Solid elements (CHEXA, CTETRA, CPENTA): index 9
   - Shell elements (CQUAD4, CTRIA3): last column
   - Data structure: [oxx, oyy, ozz, txy, tyz, txz, o1, o2, o3, von_mises]

3. Units Conversion (CRITICAL)
   - NX Nastran outputs stress in kPa, not MPa
   - Apply conversion: kPa / 1000 = MPa
   - Example: 113094.73 kPa -> 113.09 MPa

Test Results:
- Before: 0.00 MPa (FAIL)
- After:  113.09 MPa at element 83 (SUCCESS)

Files modified:
- optimization_engine/result_extractors/op2_extractor_example.py

Test files added:
- examples/test_stress_direct.py
- examples/test_stress_fix.py
- examples/debug_op2_stress.py
- STRESS_EXTRACTION_FIXED.md
- TESTING_STRESS_FIX.md
2025-11-15 11:18:03 -05:00

89 lines
2.9 KiB
Python

"""
Deep diagnostic to find where stress data is hiding in the OP2 file.
"""
from pathlib import Path
from pyNastran.op2.op2 import OP2
op2_path = Path("examples/bracket/bracket_sim1-solution_1.op2")
print("="*60)
print("DEEP OP2 STRESS DIAGNOSTIC")
print("="*60)
print(f"File: {op2_path}")
print()
op2 = OP2()
op2.read_op2(str(op2_path))
# List ALL attributes that might contain stress
print("--- SEARCHING FOR STRESS DATA ---")
print()
# Check all attributes
all_attrs = dir(op2)
stress_related = [attr for attr in all_attrs if 'stress' in attr.lower() or 'oes' in attr.lower()]
print("Attributes with 'stress' or 'oes' in name:")
for attr in stress_related:
obj = getattr(op2, attr, None)
if obj and not callable(obj):
print(f" {attr}: {type(obj)}")
if hasattr(obj, 'keys'):
print(f" Keys: {list(obj.keys())}")
if obj:
first_key = list(obj.keys())[0]
first_obj = obj[first_key]
print(f" First item type: {type(first_obj)}")
if hasattr(first_obj, 'data'):
print(f" Data shape: {first_obj.data.shape}")
print(f" Data type: {first_obj.data.dtype}")
if hasattr(first_obj, '__dict__'):
attrs = [a for a in dir(first_obj) if not a.startswith('_')]
print(f" Available methods/attrs: {attrs[:10]}...")
print()
print("--- CHECKING STANDARD STRESS TABLES ---")
standard_tables = [
'cquad4_stress',
'ctria3_stress',
'ctetra_stress',
'chexa_stress',
'cpenta_stress',
'cbar_stress',
'cbeam_stress',
]
for table_name in standard_tables:
if hasattr(op2, table_name):
table = getattr(op2, table_name)
print(f"\n{table_name}:")
print(f" Exists: {table is not None}")
print(f" Type: {type(table)}")
print(f" Bool: {bool(table)}")
if table:
print(f" Keys: {list(table.keys())}")
if table.keys():
first_key = list(table.keys())[0]
data = table[first_key]
print(f" Data type: {type(data)}")
print(f" Data shape: {data.data.shape if hasattr(data, 'data') else 'No data attr'}")
# Try to inspect the data object
if hasattr(data, 'data'):
print(f" Data min: {data.data.min():.6f}")
print(f" Data max: {data.data.max():.6f}")
# Show column-wise max
if len(data.data.shape) == 3:
print(f" Column-wise max values:")
for col in range(data.data.shape[2]):
col_max = data.data[0, :, col].max()
col_min = data.data[0, :, col].min()
print(f" Column {col}: min={col_min:.6f}, max={col_max:.6f}")
print()
print("="*60)