AnsysLink/backend/pymechanical/session_manager.py

1080 lines
43 KiB
Python

"""
ANSYS Mechanical session manager for CAE Mesh Generator
"""
import os
import time
import logging
from pathlib import Path
from typing import Optional, Dict, Any, List, Callable
from datetime import datetime
from config import ANSYS_CONFIG, TEMP_DIR
from backend.pymechanical.named_selection_manager import NamedSelectionManager
from backend.pymechanical.mesh_controller import MeshController
from backend.pymechanical.mesh_generator import MeshGenerator
from backend.pymechanical.mesh_quality_checker import MeshQualityChecker
from backend.utils.resource_manager import resource_manager, file_manager
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ANSYSSessionManager:
"""
ANSYS Mechanical session manager
This class manages ANSYS Mechanical sessions for mesh generation.
It includes both real PyMechanical integration and simulation mode
for development/testing without ANSYS installation.
"""
def __init__(self, simulation_mode: bool = False):
"""
Initialize session manager
Args:
simulation_mode: If True, simulate ANSYS operations without real ANSYS
"""
self.simulation_mode = simulation_mode
self.session = None
self.mechanical = None
self.is_session_active = False
self.current_geometry = None
self.session_start_time = None
self.temp_files = []
self.named_selection_manager = None
self.mesh_controller = None
self.mesh_generator = None
self.mesh_quality_checker = None
# Create temp directory if it doesn't exist
os.makedirs(TEMP_DIR, exist_ok=True)
logger.info(f"ANSYS Session Manager initialized (simulation_mode={simulation_mode})")
def start_session(self, batch_mode: bool = True) -> bool:
"""
Start ANSYS Mechanical session
Args:
batch_mode: Whether to start in batch mode
Returns:
True if session started successfully, False otherwise
"""
try:
logger.info("Starting ANSYS Mechanical session...")
self.session_start_time = datetime.now()
if self.simulation_mode:
# Simulate session startup
logger.info("Simulation mode: Simulating ANSYS session startup")
time.sleep(1) # Simulate startup time
self.is_session_active = True
self.session = {"simulation": True, "batch_mode": batch_mode}
logger.info("✓ Simulated ANSYS session started successfully")
return True
else:
# Real PyMechanical integration
try:
import ansys.mechanical.core as pymechanical
import os
logger.info("Launching ANSYS Mechanical...")
# Set up ANSYS environment
ansys_root = ANSYS_CONFIG.get('ansys_root', r'C:\Program Files\ANSYS Inc\v241')
os.environ['AWP_ROOT241'] = ansys_root
os.environ['ANSYS_ROOT'] = ansys_root
# Configure launch parameters
launch_options = {
'batch': batch_mode,
'cleanup_on_exit': True,
}
# Add version-specific configuration if available
if 'ansys_version' in ANSYS_CONFIG:
launch_options['version'] = ANSYS_CONFIG['ansys_version']
# Start Mechanical session
self.mechanical = pymechanical.launch_mechanical(**launch_options)
# Verify session is working
if self.mechanical:
# Test basic functionality
try:
# Check if session is alive
if hasattr(self.mechanical, 'is_alive') and self.mechanical.is_alive:
logger.info(f"ANSYS Mechanical session established and alive")
else:
logger.info(f"ANSYS Mechanical session established")
# Try to get product info
try:
product_info = self.mechanical.get_product_info()
logger.info(f"ANSYS Product info: {product_info}")
except Exception as e:
logger.debug(f"Could not get product info: {str(e)}")
self.session = self.mechanical
self.is_session_active = True
# Initialize named selection manager
self.named_selection_manager = NamedSelectionManager(self.mechanical)
# Initialize mesh controller
self.mesh_controller = MeshController(self.mechanical)
# Initialize mesh generator
self.mesh_generator = MeshGenerator(self.mechanical)
# Initialize mesh quality checker
self.mesh_quality_checker = MeshQualityChecker(self.mechanical)
logger.info("✓ Real ANSYS Mechanical session started successfully")
return True
except Exception as session_error:
logger.error(f"Failed to verify Mechanical session: {str(session_error)}")
# Try to close the session if it was partially started
try:
self.mechanical.exit()
except:
pass
return False
else:
logger.error("Failed to launch ANSYS Mechanical")
return False
except ImportError as e:
logger.error(f"PyMechanical not available: {str(e)}")
logger.info("Falling back to simulation mode")
self.simulation_mode = True
return self.start_session(batch_mode)
except Exception as e:
logger.error(f"Failed to start ANSYS Mechanical session: {str(e)}")
logger.info("Falling back to simulation mode")
self.simulation_mode = True
return self.start_session(batch_mode)
except Exception as e:
logger.error(f"Session startup error: {str(e)}")
return False
def import_geometry(self, file_path: str) -> bool:
"""
Import geometry from CAD file
Args:
file_path: Path to the CAD file
Returns:
True if import successful, False otherwise
"""
try:
if not self.is_session_active:
logger.error("No active ANSYS session")
return False
# In simulation mode, don't check for real file existence
if not self.simulation_mode and not os.path.exists(file_path):
logger.error(f"Geometry file not found: {file_path}")
return False
logger.info(f"Importing geometry from: {file_path}")
if self.simulation_mode:
# Simulate geometry import
logger.info("Simulation mode: Simulating geometry import")
time.sleep(2) # Simulate import time
# Simulate geometry validation
file_size = os.path.getsize(file_path)
if file_size == 0:
logger.error("Invalid geometry file (empty)")
return False
self.current_geometry = {
"file_path": file_path,
"file_size": file_size,
"imported_at": datetime.now(),
"simulation": True
}
logger.info("✓ Simulated geometry import completed successfully")
return True
else:
# Real PyMechanical geometry import
try:
logger.info("Importing geometry using PyMechanical...")
# Method 1: Try direct script execution
try:
# Create a script to import geometry using correct PyMechanical API
import_script = f'''
# Import geometry using PyMechanical API
geometry_import = Model.GeometryImportGroup.AddGeometryImport()
geometry_import.Import(r"{file_path}")
body_count = len(Model.Geometry.GetChildren(Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.Body, True))
print("Imported geometry with " + str(body_count) + " bodies")
'''
# Execute the script
result = self.mechanical.run_python_script(import_script)
logger.info(f"Import script result: {result}")
self.current_geometry = {
"file_path": file_path,
"imported_at": datetime.now(),
"import_method": "direct_script",
"import_result": result if result else "Import executed"
}
logger.info("✓ Real geometry import completed successfully")
return True
except Exception as script_error:
logger.warning(f"Direct script method failed: {str(script_error)}")
# Method 2: Try file upload approach
logger.info("Trying file upload approach...")
# Upload the file to the server first
uploaded_file = self.mechanical.upload(file_path)
logger.info(f"File uploaded to server: {uploaded_file}")
# Create import script using uploaded file with full path
project_dir = self.mechanical.run_python_script("ExtAPI.DataModel.Project.ProjectDirectory")
full_uploaded_path = f"{project_dir}/{uploaded_file}".replace("\\", "/")
upload_script = f'''
# Import uploaded geometry using PyMechanical API
geometry_import = Model.GeometryImportGroup.AddGeometryImport()
geometry_import.Import(r"{full_uploaded_path}")
body_count = len(Model.Geometry.GetChildren(Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.Body, True))
print("Imported uploaded geometry with " + str(body_count) + " bodies")
'''
upload_result = self.mechanical.run_python_script(upload_script)
logger.info(f"Upload import result: {upload_result}")
self.current_geometry = {
"file_path": file_path,
"uploaded_file": uploaded_file,
"imported_at": datetime.now(),
"import_method": "upload_script",
"import_result": upload_result if upload_result else "Upload import executed"
}
logger.info("✓ Real geometry import completed via upload method")
return True
except Exception as e:
logger.error(f"PyMechanical geometry import error: {str(e)}")
logger.error("This could be due to:")
logger.error("- Invalid or corrupted STEP file")
logger.error("- Unsupported geometry format")
logger.error("- ANSYS Mechanical session issues")
logger.error("- PyMechanical API version mismatch")
return False
except Exception as e:
logger.error(f"Geometry import error: {str(e)}")
return False
def validate_geometry(self) -> Dict[str, Any]:
"""
Validate imported geometry
Returns:
Dictionary with validation results
"""
try:
if not self.current_geometry:
return {
"valid": False,
"error": "No geometry imported"
}
logger.info("Validating imported geometry...")
if self.simulation_mode:
# Simulate geometry validation
time.sleep(0.5)
validation_result = {
"valid": True,
"file_path": self.current_geometry["file_path"],
"file_size_mb": round(self.current_geometry["file_size"] / (1024 * 1024), 2),
"surface_count": 42, # Simulated values
"volume_count": 1,
"feature_count": 15,
"simulation": True
}
logger.info("✓ Simulated geometry validation completed")
return validation_result
else:
# Real geometry validation using PyMechanical
try:
# Get geometry information using PyMechanical script
validation_script = '''
# Get geometry validation information
body_count = len(Model.Geometry.GetChildren(Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.Body, True))
surface_count = body_count # Simplified - assume each body has surfaces
volume_count = body_count # Simplified - assume each body has volume
print("Bodies: " + str(body_count) + ", Surfaces: " + str(surface_count) + ", Volumes: " + str(volume_count))
'''
validation_result_str = self.mechanical.run_python_script(validation_script)
logger.info(f"Validation script result: {validation_result_str}")
# Parse the result or use default values
body_count = 1 # Default value
surface_count = 1
volume_count = 1
# Try to extract numbers from the result string
if validation_result_str:
import re
numbers = re.findall(r'\d+', str(validation_result_str))
if len(numbers) >= 3:
body_count = int(numbers[0])
surface_count = int(numbers[1])
volume_count = int(numbers[2])
validation_result = {
"valid": True,
"file_path": self.current_geometry["file_path"],
"body_count": body_count,
"surface_count": surface_count,
"volume_count": volume_count,
"imported_at": self.current_geometry["imported_at"].isoformat(),
"import_method": self.current_geometry.get("import_method", "unknown")
}
logger.info("✓ Real geometry validation completed")
return validation_result
except Exception as e:
logger.error(f"Geometry validation error: {str(e)}")
return {
"valid": False,
"error": str(e)
}
except Exception as e:
logger.error(f"Validation error: {str(e)}")
return {
"valid": False,
"error": str(e)
}
def create_named_selections(self) -> Dict[str, Any]:
"""
Create named selections for blade geometry
Returns:
Dictionary with creation results
"""
try:
if not self.is_session_active:
logger.error("No active ANSYS session")
return {
"success": False,
"error": "No active ANSYS session"
}
if not self.current_geometry:
logger.error("No geometry imported")
return {
"success": False,
"error": "No geometry imported"
}
logger.info("Creating named selections for blade geometry...")
if self.simulation_mode:
# Simulate named selection creation
logger.info("Simulation mode: Simulating named selection creation")
time.sleep(1)
simulated_result = {
"success": True,
"selections_created": ["leading_edge", "trailing_edge", "blade_root", "blade_surfaces"],
"selections_failed": [],
"total_selections": 4,
"created_at": datetime.now(),
"simulation": True
}
logger.info("✓ Simulated named selection creation completed")
return simulated_result
else:
# Real named selection creation using PyMechanical
if not self.named_selection_manager:
logger.error("Named selection manager not initialized")
return {
"success": False,
"error": "Named selection manager not initialized"
}
result = self.named_selection_manager.create_blade_named_selections()
if result["success"]:
logger.info(f"✓ Named selections created successfully: {result['total_selections']} selections")
else:
logger.error(f"Named selection creation failed: {result.get('error', 'Unknown error')}")
return result
except Exception as e:
logger.error(f"Named selection creation error: {str(e)}")
return {
"success": False,
"error": str(e),
"selections_created": [],
"selections_failed": [],
"total_selections": 0,
"created_at": datetime.now()
}
def get_named_selections_info(self) -> Dict[str, Any]:
"""
Get information about created named selections
Returns:
Dictionary with named selection information
"""
try:
if not self.is_session_active:
return {
"success": False,
"error": "No active ANSYS session"
}
if self.simulation_mode:
# Simulate getting named selection info
return {
"success": True,
"created_selections": {
"leading_edge": {"description": "Simulated leading edge", "method": "curvature_based"},
"trailing_edge": {"description": "Simulated trailing edge", "method": "angle_based"},
"blade_root": {"description": "Simulated blade root", "method": "location_based"},
"blade_surfaces": {"description": "Simulated blade surfaces", "method": "surface_based"}
},
"total_count": 4,
"simulation": True
}
else:
if not self.named_selection_manager:
return {
"success": False,
"error": "Named selection manager not initialized"
}
return self.named_selection_manager.get_named_selections_info()
except Exception as e:
logger.error(f"Error getting named selections info: {str(e)}")
return {
"success": False,
"error": str(e)
}
def validate_named_selections(self) -> Dict[str, Any]:
"""
Validate created named selections
Returns:
Dictionary with validation results
"""
try:
if not self.is_session_active:
return {
"success": False,
"error": "No active ANSYS session"
}
if self.simulation_mode:
# Simulate validation
return {
"success": True,
"validation_result": "All 4 named selections validated successfully",
"validated_at": datetime.now(),
"simulation": True
}
else:
if not self.named_selection_manager:
return {
"success": False,
"error": "Named selection manager not initialized"
}
return self.named_selection_manager.validate_named_selections()
except Exception as e:
logger.error(f"Named selection validation error: {str(e)}")
return {
"success": False,
"error": str(e)
}
def apply_mesh_controls(self, named_selections: List[str] = None) -> Dict[str, Any]:
"""
Apply mesh controls for blade geometry
Args:
named_selections: List of named selections to use for controls
Returns:
Dictionary with mesh control application results
"""
try:
if not self.is_session_active:
logger.error("No active ANSYS session")
return {
"success": False,
"error": "No active ANSYS session"
}
if not self.current_geometry:
logger.error("No geometry imported")
return {
"success": False,
"error": "No geometry imported"
}
logger.info("Applying mesh controls for blade geometry...")
if self.simulation_mode:
# Simulate mesh control application
logger.info("Simulation mode: Simulating mesh control application")
time.sleep(2)
simulated_result = {
"success": True,
"controls_applied": ["parameter_calculation", "global_settings", "local_refinement", "inflation_layers"],
"controls_failed": [],
"mesh_parameters": {
"global_element_size": 2.0,
"curvature_angle": 25.0,
"inflation_layers": 5,
"growth_rate": 1.15
},
"applied_at": datetime.now(),
"simulation": True
}
logger.info("✓ Simulated mesh control application completed")
return simulated_result
else:
# Real mesh control application using PyMechanical
if not self.mesh_controller:
logger.error("Mesh controller not initialized")
return {
"success": False,
"error": "Mesh controller not initialized"
}
# Use provided named selections or get from named selection manager
if named_selections is None:
if self.named_selection_manager:
# Get created named selections
info_result = self.named_selection_manager.get_named_selections_info()
if info_result.get('success'):
named_selections = list(info_result.get('created_selections', {}).keys())
else:
named_selections = ['leading_edge', 'trailing_edge', 'blade_root', 'blade_surfaces']
else:
named_selections = ['leading_edge', 'trailing_edge', 'blade_root', 'blade_surfaces']
result = self.mesh_controller.apply_all_mesh_controls(named_selections)
if result["success"]:
logger.info(f"✓ Mesh controls applied successfully: {len(result['controls_applied'])} controls")
else:
logger.warning(f"⚠ Mesh controls partially applied: {result.get('controls_applied', [])} successful, {result.get('controls_failed', [])} failed")
return result
except Exception as e:
logger.error(f"Mesh control application error: {str(e)}")
return {
"success": False,
"error": str(e),
"controls_applied": [],
"controls_failed": ["all"],
"applied_at": datetime.now()
}
def get_mesh_control_summary(self) -> Dict[str, Any]:
"""
Get summary of applied mesh controls
Returns:
Dictionary with mesh control summary
"""
try:
if not self.is_session_active:
return {
"success": False,
"error": "No active ANSYS session"
}
if self.simulation_mode:
# Simulate mesh control summary
return {
"success": True,
"mesh_parameters": {
"global_element_size": 2.0,
"curvature_angle": 25.0,
"inflation_layers": 5,
"growth_rate": 1.15
},
"applied_controls": {
"global_settings": {"applied": True},
"local_refinement": {"applied": True, "regions": 3},
"inflation_layers": {"applied": True, "surfaces": 1}
},
"geometry_info": {
"min_feature_size": 5.0,
"max_dimension": 100.0
},
"simulation": True
}
else:
if not self.mesh_controller:
return {
"success": False,
"error": "Mesh controller not initialized"
}
return self.mesh_controller.get_mesh_control_summary()
except Exception as e:
logger.error(f"Failed to get mesh control summary: {str(e)}")
return {
"success": False,
"error": str(e)
}
def generate_mesh(self, progress_callback: Optional[Callable[[float, str], None]] = None) -> Dict[str, Any]:
"""
Generate mesh for the imported geometry
Args:
progress_callback: Optional callback for progress updates
Returns:
Dictionary with mesh generation results
"""
try:
if not self.is_session_active:
logger.error("No active ANSYS session")
return {
"success": False,
"error": "No active ANSYS session"
}
if not self.current_geometry:
logger.error("No geometry imported")
return {
"success": False,
"error": "No geometry imported"
}
logger.info("Starting mesh generation...")
if self.simulation_mode:
# Simulate mesh generation
logger.info("Simulation mode: Simulating mesh generation")
# Simulate progress updates
if progress_callback:
progress_steps = [
(10.0, "Preparing mesh generation..."),
(30.0, "Generating mesh..."),
(60.0, "Creating elements..."),
(80.0, "Optimizing mesh quality..."),
(100.0, "Mesh generation completed")
]
for progress, message in progress_steps:
progress_callback(progress, message)
time.sleep(0.5)
simulated_result = {
"success": True,
"status": "completed",
"element_count": 12500,
"node_count": 18750,
"generation_time": 15.5,
"progress_percentage": 100.0,
"started_at": datetime.now().isoformat(),
"completed_at": datetime.now().isoformat(),
"simulation": True
}
logger.info("✓ Simulated mesh generation completed")
return simulated_result
else:
# Real mesh generation using PyMechanical
if not self.mesh_generator:
logger.error("Mesh generator not initialized")
return {
"success": False,
"error": "Mesh generator not initialized"
}
# Set progress callback if provided
if progress_callback:
self.mesh_generator.set_progress_callback(progress_callback)
# Generate mesh
result = self.mesh_generator.generate_mesh()
# Convert result to dictionary
result_dict = {
"success": result.success,
"status": result.status.value,
"element_count": result.element_count,
"node_count": result.node_count,
"generation_time": result.generation_time,
"progress_percentage": result.progress_percentage,
"started_at": result.started_at.isoformat() if result.started_at else None,
"completed_at": result.completed_at.isoformat() if result.completed_at else None,
"error_message": result.error_message,
"warnings": result.warnings
}
if result.success:
logger.info(f"✓ Mesh generation completed: {result.element_count} elements, {result.node_count} nodes")
else:
logger.error(f"✗ Mesh generation failed: {result.error_message}")
return result_dict
except Exception as e:
logger.error(f"Mesh generation error: {str(e)}")
return {
"success": False,
"error": str(e),
"status": "failed",
"completed_at": datetime.now().isoformat()
}
def get_mesh_statistics(self) -> Dict[str, Any]:
"""
Get mesh statistics
Returns:
Dictionary with mesh statistics
"""
try:
if not self.is_session_active:
return {
"success": False,
"error": "No active ANSYS session"
}
if self.simulation_mode:
# Simulate mesh statistics
return {
"success": True,
"element_count": 12500,
"node_count": 18750,
"generation_time": 15.5,
"has_mesh": True,
"status": "completed",
"retrieved_at": datetime.now().isoformat(),
"simulation": True
}
else:
if not self.mesh_generator:
return {
"success": False,
"error": "Mesh generator not initialized"
}
statistics = self.mesh_generator.get_mesh_statistics()
statistics["success"] = True
return statistics
except Exception as e:
logger.error(f"Failed to get mesh statistics: {str(e)}")
return {
"success": False,
"error": str(e)
}
def check_mesh_quality(self) -> Dict[str, Any]:
"""
Perform mesh quality check
Returns:
Dictionary with quality check results
"""
try:
if not self.is_session_active:
logger.error("No active ANSYS session")
return {
"success": False,
"error": "No active ANSYS session"
}
logger.info("Starting mesh quality check...")
if self.simulation_mode:
# Simulate quality check
logger.info("Simulation mode: Simulating mesh quality check")
time.sleep(1)
simulated_result = {
"success": True,
"overall_status": "PASSED",
"quality_score": 85.5,
"metrics": {
"min_element_quality": 0.25,
"max_aspect_ratio": 18.5,
"max_skewness": 0.75,
"min_orthogonal_quality": 0.18,
"average_element_quality": 0.65,
"failed_elements_count": 12,
"total_elements": 6500,
"failed_elements_percentage": 0.18
},
"thresholds": {
"min_element_quality": 0.2,
"max_aspect_ratio": 20,
"max_skewness": 0.8,
"min_orthogonal_quality": 0.15
},
"recommendations": [
"Mesh quality is acceptable for analysis",
"Consider local refinement for critical areas"
],
"warnings": [
"Element quality acceptable: 0.250",
"Aspect ratio acceptable: 18.50",
"Failed elements acceptable: 0.2%"
],
"critical_issues": [],
"check_time": datetime.now().isoformat(),
"simulation": True
}
logger.info("✓ Simulated mesh quality check completed")
return simulated_result
else:
# Real mesh quality check using PyMechanical
if not self.mesh_quality_checker:
logger.error("Mesh quality checker not initialized")
return {
"success": False,
"error": "Mesh quality checker not initialized"
}
quality_result = self.mesh_quality_checker.check_mesh_quality()
summary = self.mesh_quality_checker.get_quality_summary(quality_result)
result = {
"success": True,
**summary
}
if quality_result.passed:
logger.info(f"✓ Mesh quality check passed: score {summary.get('quality_score', 0):.1f}")
else:
logger.warning(f"⚠ Mesh quality check failed: {len(quality_result.critical_issues)} critical issues")
return result
except Exception as e:
logger.error(f"Mesh quality check error: {str(e)}")
return {
"success": False,
"error": str(e),
"overall_status": "ERROR",
"check_time": datetime.now().isoformat()
}
def validate_mesh_generation_setup(self) -> Dict[str, Any]:
"""
Validate that mesh generation setup is ready
Returns:
Dictionary with validation results
"""
try:
if not self.is_session_active:
return {
"success": False,
"error": "No active ANSYS session",
"ready_for_generation": False
}
if self.simulation_mode:
# Simulate validation
return {
"success": True,
"geometry_available": True,
"mesh_object_exists": True,
"global_settings_applied": True,
"local_controls_applied": True,
"ready_for_generation": True,
"simulation": True
}
else:
if not self.mesh_generator:
return {
"success": False,
"error": "Mesh generator not initialized",
"ready_for_generation": False
}
validation = self.mesh_generator.validate_mesh_generation_setup()
validation["success"] = True
return validation
except Exception as e:
logger.error(f"Setup validation failed: {str(e)}")
return {
"success": False,
"error": str(e),
"ready_for_generation": False
}
def close_session(self) -> bool:
"""
Close ANSYS Mechanical session
Returns:
True if session closed successfully, False otherwise
"""
try:
if not self.is_session_active:
logger.info("No active session to close")
return True
logger.info("Closing ANSYS Mechanical session...")
# Clean up temporary files first
self.cleanup_temp_files()
if self.simulation_mode:
# Simulate session cleanup
time.sleep(0.5)
self.session = None
self.is_session_active = False
self.current_geometry = None
logger.info("✓ Simulated ANSYS session closed successfully")
else:
# Real PyMechanical session cleanup
try:
# Register session with resource manager for cleanup
if self.mechanical:
resource_manager.register_ansys_session(self.mechanical)
self.mechanical.exit()
self.mechanical = None
self.session = None
self.is_session_active = False
self.current_geometry = None
logger.info("✓ Real ANSYS session closed successfully")
except Exception as e:
logger.error(f"Session close error: {str(e)}")
return False
return True
except Exception as e:
logger.error(f"Session close error: {str(e)}")
return False
def cleanup_temp_files(self) -> bool:
"""
Clean up temporary files created during session
Returns:
True if cleanup successful, False otherwise
"""
try:
logger.info("Cleaning up temporary files...")
# Register temp files with resource manager
for temp_file in self.temp_files:
resource_manager.register_temp_file(temp_file)
# Use resource manager for cleanup
cleanup_results = resource_manager.cleanup_temp_files()
# Clear local temp files list
self.temp_files.clear()
# Clean up temp directory if empty
try:
if os.path.exists(TEMP_DIR) and not os.listdir(TEMP_DIR):
os.rmdir(TEMP_DIR)
logger.debug(f"Removed empty temp directory: {TEMP_DIR}")
except Exception as e:
logger.debug(f"Could not remove temp directory: {str(e)}")
cleaned_count = cleanup_results.get('cleaned', 0)
failed_count = cleanup_results.get('failed', 0)
logger.info(f"✓ Cleanup completed: {cleaned_count} files cleaned, {failed_count} failed")
return failed_count == 0
except Exception as e:
logger.error(f"Cleanup error: {str(e)}")
return False
def get_session_info(self) -> Dict[str, Any]:
"""
Get current session information
Returns:
Dictionary with session information
"""
session_time = None
if self.session_start_time:
session_time = (datetime.now() - self.session_start_time).total_seconds()
return {
"is_active": self.is_session_active,
"simulation_mode": self.simulation_mode,
"session_time": session_time,
"has_geometry": self.current_geometry is not None,
"geometry_info": self.current_geometry if self.current_geometry else None,
"temp_files_count": len(self.temp_files)
}
def __enter__(self):
"""Context manager entry"""
self.start_session()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Context manager exit"""
self.close_session()
self.cleanup_temp_files()