""" Extract natural frequencies from modal analysis Auto-generated by Atomizer Phase 3 - pyNastran Research Agent Pattern: eigenvalue_extraction Element Type: General Result Type: eigenvalues API: model.eigenvalues[subcase] """ from pathlib import Path from typing import Dict, Any import numpy as np from pyNastran.op2.op2 import OP2 def extract_frequency(op2_file: Path, subcase: int = 1, mode_number: int = 1): """ Extract natural frequency results from modal analysis OP2 file. Args: op2_file: Path to OP2 file subcase: Subcase ID for modal analysis (default: 1) mode_number: Which mode to extract (1-indexed, default: 1 for fundamental frequency) Returns: Dictionary containing frequency data """ from pyNastran.op2.op2 import OP2 import numpy as np model = OP2() model.read_op2(str(op2_file)) # Access eigenvalues from modal analysis # NX Nastran often uses empty string '' as subcase key available_subcases = list(model.eigenvalues.keys()) if not available_subcases: raise ValueError(f"No eigenvalue data found in OP2 file: {op2_file}") # Use the first available subcase (often '' for NX Nastran) actual_subcase = available_subcases[0] eigenvalues = model.eigenvalues[actual_subcase] # Extract frequency data for the specified mode # RealEigenvalues object has different attributes than expected # Try to access frequencies - could be in different formats # Mode number is 1-indexed, array is 0-indexed mode_idx = mode_number - 1 # Try different attribute names for frequencies if hasattr(eigenvalues, 'cycles'): frequencies = eigenvalues.cycles elif hasattr(eigenvalues, 'frequencies'): frequencies = eigenvalues.frequencies else: # Try to get eigenvalues and convert to frequency if hasattr(eigenvalues, 'eigenvalues'): # eigenvalue (lambda) = (2*pi*f)^2, so f = sqrt(lambda) / (2*pi) eigenvals = eigenvalues.eigenvalues frequencies = np.sqrt(np.abs(eigenvals)) / (2.0 * np.pi) else: raise ValueError(f"Cannot find frequency data in eigenvalues object. Available attributes: {dir(eigenvalues)}") if mode_idx >= len(frequencies): raise ValueError(f"Mode {mode_number} not found. Only {len(frequencies)} modes available.") frequency = frequencies[mode_idx] # Hz # Try to get eigenvalue if available if hasattr(eigenvalues, 'eigenvalues'): eigenvalue = eigenvalues.eigenvalues[mode_idx] elif hasattr(eigenvalues, 'eigrs'): eigenvalue = eigenvalues.eigrs[mode_idx] else: eigenvalue = (2.0 * np.pi * frequency) ** 2 # Convert back from frequency # Also return all frequencies for reference all_frequencies = list(frequencies) return { 'frequency': float(frequency), 'mode_number': int(mode_number), 'eigenvalue': float(eigenvalue), 'all_frequencies': all_frequencies, 'n_modes': len(all_frequencies) } if __name__ == '__main__': # Example usage import sys if len(sys.argv) > 1: op2_file = Path(sys.argv[1]) mode_num = int(sys.argv[2]) if len(sys.argv) > 2 else 1 result = extract_frequency(op2_file, mode_number=mode_num) print(f"Extraction result: {result}") else: print(f"Usage: python {sys.argv[0]} [mode_number]")