feat: Comprehensive expression extraction and OP2 result extractor example
Enhanced expression extraction to find ALL named expressions in .prt files, not just specific format. Added pyNastran-based result extraction example. Expression Extraction Improvements: - Updated regex to handle all NX expression format variations: * #(Type [units]) name: value; * (Type [units]) name: value; * *(Type [units]) name: value; * ((Type [units]) name: value; - Added Root:expression_name: pattern detection - Finds expressions even when value is not immediately available - Deduplication to avoid duplicates - Filters out NX internal names Test Results with Bracket.prt: - Previously: 1 expression (tip_thickness only) - Now: 5 expressions found: * support_angle = 30.0 degrees * tip_thickness = 20.0 mm * p3 = 10.0 mm * support_blend_radius = 10.0 mm * p11 (reference found, value unknown) OP2 Result Extraction (pyNastran): - Created example extractor: op2_extractor_example.py - Functions for common optimization metrics: * extract_max_displacement() - max displacement magnitude on any node * extract_max_stress() - von Mises or max principal stress * extract_mass() - total mass and center of gravity - Handles multiple element types (CQUAD4, CTRIA3, CTETRA, etc.) - Returns structured JSON for optimization engine integration - Command-line tool for testing with real OP2 files Usage: python optimization_engine/result_extractors/op2_extractor_example.py <file.op2> Integration Ready: - pyNastran already in requirements.txt - Result extractor pattern established - Can be used as template for custom metrics Next Steps: - Integrate result extractors into MCP tool framework - Add safety factor calculations - Support for thermal, modal results
This commit is contained in:
@@ -222,21 +222,54 @@ class SimFileParser:
|
||||
# Try to decode as latin-1 (preserves all byte values)
|
||||
text_content = content.decode('latin-1', errors='ignore')
|
||||
|
||||
# Pattern 1: NX native format: #(Number [mm]) tip_thickness: 20;
|
||||
# Captures: type, units, name, value
|
||||
nx_pattern = r'#\((\w+)\s*\[([^\]]*)\]\)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)'
|
||||
# Pattern 1: NX native format with variations:
|
||||
# #(Number [mm]) tip_thickness: 20;
|
||||
# (Number [mm]) p3: 10;
|
||||
# *(Number [mm]) support_blend_radius: 10;
|
||||
# ((Number [degrees]) support_angle: 30;
|
||||
# Prefix can be: #(, *(, (, ((
|
||||
nx_pattern = r'[#*\(]*\((\w+)\s*\[([^\]]*)\]\)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)'
|
||||
|
||||
# Use set to avoid duplicates
|
||||
expr_names_seen = set()
|
||||
|
||||
for match in re.finditer(nx_pattern, text_content):
|
||||
expr_type, units, name, value = match.groups()
|
||||
expressions.append({
|
||||
'name': name,
|
||||
'value': float(value),
|
||||
'units': units,
|
||||
'type': expr_type,
|
||||
'source': 'prt_file_nx_format'
|
||||
})
|
||||
if name not in expr_names_seen:
|
||||
expr_names_seen.add(name)
|
||||
expressions.append({
|
||||
'name': name,
|
||||
'value': float(value),
|
||||
'units': units,
|
||||
'type': expr_type,
|
||||
'source': 'prt_file_nx_format'
|
||||
})
|
||||
|
||||
# Pattern 2: Fallback - simple name=value pattern
|
||||
# Pattern 2: Find expression names from Root: references
|
||||
# Format: Root:expression_name:
|
||||
root_pattern = r'Root:([a-zA-Z_][a-zA-Z0-9_]{2,}):'
|
||||
potential_expr_names = set()
|
||||
|
||||
for match in re.finditer(root_pattern, text_content):
|
||||
name = match.group(1)
|
||||
# Filter out common NX internal names
|
||||
if name not in ['index', '%%Name', '%%ug_objects_for_', 'WorldModifier']:
|
||||
if not name.startswith('%%'):
|
||||
potential_expr_names.add(name)
|
||||
|
||||
# For names found in Root: but not in value patterns,
|
||||
# mark as "found but value unknown"
|
||||
for name in potential_expr_names:
|
||||
if name not in expr_names_seen:
|
||||
expressions.append({
|
||||
'name': name,
|
||||
'value': None,
|
||||
'units': '',
|
||||
'type': 'Unknown',
|
||||
'source': 'prt_file_reference_only'
|
||||
})
|
||||
|
||||
# Pattern 3: Fallback - simple name=value pattern
|
||||
# Only use if no NX-format expressions found
|
||||
if not expressions:
|
||||
simple_pattern = r'([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)'
|
||||
|
||||
Reference in New Issue
Block a user