AnsysLink/backend/pymechanical/named_selection_manager.py

414 lines
15 KiB
Python

"""
Named Selection Manager for CAE Mesh Generator
This module handles automatic creation of named selections for blade geometry,
specifically identifying leading edge, trailing edge, and blade root regions.
"""
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime
logger = logging.getLogger(__name__)
class NamedSelectionManager:
"""
Manager for creating and managing named selections in ANSYS Mechanical
This class provides functionality to automatically identify and create
named selections for blade geometry features like leading edge, trailing edge,
and blade root regions.
"""
def __init__(self, mechanical_session):
"""
Initialize named selection manager
Args:
mechanical_session: Active PyMechanical session
"""
self.mechanical = mechanical_session
self.created_selections = {}
self.selection_criteria = {
'leading_edge': {
'description': 'High curvature edges at blade leading edge',
'method': 'curvature_based'
},
'trailing_edge': {
'description': 'Sharp edges at blade trailing edge',
'method': 'angle_based'
},
'blade_root': {
'description': 'Connection surfaces at blade root',
'method': 'location_based'
},
'blade_surfaces': {
'description': 'External blade surfaces',
'method': 'surface_based'
}
}
logger.info("Named Selection Manager initialized")
def create_blade_named_selections(self) -> Dict[str, Any]:
"""
Create all named selections for blade geometry
Returns:
Dictionary with creation results and selection information
"""
try:
logger.info("Creating blade named selections...")
results = {
'success': True,
'selections_created': [],
'selections_failed': [],
'total_selections': 0,
'created_at': datetime.now()
}
# Create each named selection
for selection_name, criteria in self.selection_criteria.items():
try:
logger.info(f"Creating named selection: {selection_name}")
success = self._create_named_selection(
name=selection_name,
description=criteria['description'],
method=criteria['method']
)
if success:
results['selections_created'].append(selection_name)
logger.info(f"✓ Created named selection: {selection_name}")
else:
results['selections_failed'].append(selection_name)
logger.warning(f"✗ Failed to create named selection: {selection_name}")
except Exception as e:
logger.error(f"Error creating named selection {selection_name}: {str(e)}")
results['selections_failed'].append(selection_name)
results['total_selections'] = len(results['selections_created'])
if results['selections_failed']:
results['success'] = len(results['selections_created']) > 0
logger.warning(f"Some named selections failed: {results['selections_failed']}")
logger.info(f"✓ Named selection creation completed: {results['total_selections']} created")
return results
except Exception as e:
logger.error(f"Named selection creation failed: {str(e)}")
return {
'success': False,
'error': str(e),
'selections_created': [],
'selections_failed': list(self.selection_criteria.keys()),
'total_selections': 0,
'created_at': datetime.now()
}
def _create_named_selection(self, name: str, description: str, method: str) -> bool:
"""
Create a single named selection using PyMechanical API
Args:
name: Name of the selection
description: Description of the selection
method: Method to use for selection (curvature_based, angle_based, etc.)
Returns:
True if creation successful, False otherwise
"""
try:
# Create named selection script based on method
if method == 'curvature_based':
script = self._create_curvature_based_selection_script(name, description)
elif method == 'angle_based':
script = self._create_angle_based_selection_script(name, description)
elif method == 'location_based':
script = self._create_location_based_selection_script(name, description)
elif method == 'surface_based':
script = self._create_surface_based_selection_script(name, description)
else:
logger.error(f"Unknown selection method: {method}")
return False
# Execute the script
result = self.mechanical.run_python_script(script)
logger.debug(f"Named selection script result for {name}: {result}")
# Store selection info
self.created_selections[name] = {
'description': description,
'method': method,
'created_at': datetime.now(),
'script_result': result
}
return True
except Exception as e:
logger.error(f"Failed to create named selection {name}: {str(e)}")
return False
def _create_curvature_based_selection_script(self, name: str, description: str) -> str:
"""Create script for curvature-based selection (leading edge)"""
return f'''
# Create curvature-based named selection for {name}
try:
# Create named selection
selection = Model.AddNamedSelection()
selection.Name = "{name}"
selection.ScopingMethod = GeometryDefineByType.Worksheet
# Set up criteria for high curvature edges
criteria = selection.GenerationCriteria
criterion = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion()
criterion.Active = True
criterion.Action = SelectionActionType.Add
criterion.EntityType = SelectionType.GeoEdge
criterion.Criterion = SelectionCriterionType.Size
criterion.Operator = SelectionOperatorType.LessThan
criterion.Value = Quantity("5 [mm]")
criteria.Add(criterion)
selection.Generate()
print("Created {name} named selection successfully")
except Exception as e:
print("Error creating {name} selection: " + str(e))
'''
def _create_angle_based_selection_script(self, name: str, description: str) -> str:
"""Create script for angle-based selection (trailing edge)"""
return f'''
# Create angle-based named selection for {name}
try:
# Create named selection
selection = Model.AddNamedSelection()
selection.Name = "{name}"
selection.ScopingMethod = GeometryDefineByType.Worksheet
# Set up criteria for sharp edges
criteria = selection.GenerationCriteria
criterion = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion()
criterion.Active = True
criterion.Action = SelectionActionType.Add
criterion.EntityType = SelectionType.GeoEdge
criterion.Criterion = SelectionCriterionType.Size
criterion.Operator = SelectionOperatorType.LessThan
criterion.Value = Quantity("3 [mm]")
criteria.Add(criterion)
selection.Generate()
print("Created {name} named selection successfully")
except Exception as e:
print("Error creating {name} selection: " + str(e))
'''
def _create_location_based_selection_script(self, name: str, description: str) -> str:
"""Create script for location-based selection (blade root)"""
return f'''
# Create location-based named selection for {name}
try:
# Create named selection
selection = Model.AddNamedSelection()
selection.Name = "{name}"
selection.ScopingMethod = GeometryDefineByType.Worksheet
# Set up criteria for surfaces at specific location (bottom/root)
criteria = selection.GenerationCriteria
criterion = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion()
criterion.Active = True
criterion.Action = SelectionActionType.Add
criterion.EntityType = SelectionType.GeoFace
criterion.Criterion = SelectionCriterionType.LocationZ
criterion.Operator = SelectionOperatorType.LessThan
criterion.Value = Quantity("-100 [mm]")
criteria.Add(criterion)
selection.Generate()
print("Created {name} named selection successfully")
except Exception as e:
print("Error creating {name} selection: " + str(e))
'''
def _create_surface_based_selection_script(self, name: str, description: str) -> str:
"""Create script for surface-based selection (blade surfaces)"""
return f'''
# Create surface-based named selection for {name}
try:
# Create named selection
selection = Model.AddNamedSelection()
selection.Name = "{name}"
selection.ScopingMethod = GeometryDefineByType.Worksheet
# Set up criteria for all external surfaces
criteria = selection.GenerationCriteria
criterion = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion()
criterion.Active = True
criterion.Action = SelectionActionType.Add
criterion.EntityType = SelectionType.GeoFace
criterion.Criterion = SelectionCriterionType.Size
criterion.Operator = SelectionOperatorType.GreaterThan
criterion.Value = Quantity("1 [mm^2]")
criteria.Add(criterion)
selection.Generate()
print("Created {name} named selection successfully")
except Exception as e:
print("Error creating {name} selection: " + str(e))
'''
def get_named_selections_info(self) -> Dict[str, Any]:
"""
Get information about created named selections
Returns:
Dictionary with named selection information
"""
try:
# Get named selections from Mechanical
info_script = '''
# Get named selection information
selections_info = []
named_selections = Model.GetChildren(Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.NamedSelection, True)
for selection in named_selections:
try:
info = {
"name": selection.Name,
"entity_count": len(selection.Ids) if hasattr(selection, 'Ids') else 0,
"scoping_method": str(selection.ScopingMethod) if hasattr(selection, 'ScopingMethod') else "Unknown"
}
selections_info.append(info)
print("Selection: " + selection.Name + ", Entities: " + str(info["entity_count"]))
except Exception as e:
print("Error getting info for selection: " + str(e))
print("Total named selections: " + str(len(selections_info)))
'''
result = self.mechanical.run_python_script(info_script)
logger.info(f"Named selections info: {result}")
return {
'success': True,
'created_selections': dict(self.created_selections),
'script_result': result,
'total_count': len(self.created_selections)
}
except Exception as e:
logger.error(f"Failed to get named selections info: {str(e)}")
return {
'success': False,
'error': str(e),
'created_selections': dict(self.created_selections),
'total_count': len(self.created_selections)
}
def validate_named_selections(self) -> Dict[str, Any]:
"""
Validate that named selections were created successfully
Returns:
Dictionary with validation results
"""
try:
logger.info("Validating named selections...")
validation_script = '''
# Validate named selections
validation_results = {}
expected_selections = ["leading_edge", "trailing_edge", "blade_root", "blade_surfaces"]
named_selections = Model.GetChildren(Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.NamedSelection, True)
existing_names = [sel.Name for sel in named_selections]
for expected in expected_selections:
if expected in existing_names:
# Find the selection and get its info
selection = next((sel for sel in named_selections if sel.Name == expected), None)
if selection:
entity_count = len(selection.Ids) if hasattr(selection, 'Ids') else 0
validation_results[expected] = {
"exists": True,
"entity_count": entity_count,
"valid": entity_count > 0
}
print("" + expected + ": " + str(entity_count) + " entities")
else:
validation_results[expected] = {"exists": False, "entity_count": 0, "valid": False}
print("" + expected + ": Not found")
else:
validation_results[expected] = {"exists": False, "entity_count": 0, "valid": False}
print("" + expected + ": Not found")
total_valid = sum(1 for result in validation_results.values() if result["valid"])
print("Validation complete: " + str(total_valid) + "/" + str(len(expected_selections)) + " selections valid")
'''
result = self.mechanical.run_python_script(validation_script)
logger.info(f"Validation result: {result}")
return {
'success': True,
'validation_result': result,
'validated_at': datetime.now()
}
except Exception as e:
logger.error(f"Named selection validation failed: {str(e)}")
return {
'success': False,
'error': str(e),
'validated_at': datetime.now()
}
def clear_named_selections(self) -> bool:
"""
Clear all created named selections
Returns:
True if successful, False otherwise
"""
try:
logger.info("Clearing named selections...")
clear_script = '''
# Clear all named selections
named_selections = Model.GetChildren(Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.NamedSelection, True)
cleared_count = 0
for selection in named_selections:
try:
selection.Delete()
cleared_count += 1
print("Deleted selection: " + selection.Name)
except Exception as e:
print("Error deleting selection: " + str(e))
print("Cleared " + str(cleared_count) + " named selections")
'''
result = self.mechanical.run_python_script(clear_script)
logger.info(f"Clear result: {result}")
# Clear local tracking
self.created_selections.clear()
return True
except Exception as e:
logger.error(f"Failed to clear named selections: {str(e)}")
return False