""" Check actual values from OP2 to understand what's correct """ from pyNastran.op2.op2 import OP2 from pyNastran.bdf.bdf import BDF import numpy as np print("="*60) print("CHECKING ACTUAL FEA VALUES") print("="*60) # Load OP2 op2_file = 'test_case_beam/output/model.op2' print(f"\nLoading OP2: {op2_file}") op2 = OP2() op2.read_op2(op2_file) # Load BDF bdf_file = 'test_case_beam/input/model.bdf' print(f"Loading BDF: {bdf_file}") bdf = BDF() bdf.read_bdf(bdf_file) print("\n1. UNIT SYSTEM:") print("-"*60) if hasattr(bdf, 'params') and 'UNITSYS' in bdf.params: unitsys = str(bdf.params['UNITSYS'].values[0]) print(f" PARAM UNITSYS: {unitsys}") if 'MN' in unitsys and 'MM' in unitsys: print(" This is MegaNewton-Millimeter system:") print(" - Length: mm") print(" - Force: MN (MegaNewton)") print(" - Stress: Pa (base SI)") print(" - Mass: tonne") else: print(" No UNITSYS parameter found") print("\n2. MATERIAL PROPERTIES:") print("-"*60) if hasattr(bdf, 'materials') and bdf.materials: mat = list(bdf.materials.values())[0] print(f" Material ID: {mat.mid}") print(f" Type: {mat.type}") if hasattr(mat, 'e') and mat.e: print(f" Young's modulus E: {mat.e:.2e}") print(f" -> E = {mat.e/1e9:.1f} GPa (if units are Pa)") print(f" -> E = {mat.e/1e6:.1f} GPa (if units are kPa)") print(f" -> E = {mat.e/1e3:.1f} GPa (if units are MPa)") print(f" Steel E ~= 200 GPa, so units must be Pa") print("\n3. APPLIED FORCES FROM BDF:") print("-"*60) total_force = 0 n_forces = 0 if hasattr(bdf, 'loads') and bdf.loads: for load_id, load_list in bdf.loads.items(): for load in load_list: if hasattr(load, 'mag'): print(f" Load ID {load_id}, Node {load.node}: {load.mag:.2e} (unit depends on UNITSYS)") total_force += abs(load.mag) n_forces += 1 if n_forces >= 3: break if n_forces >= 3: break print(f" Total applied force (first 3): {total_force:.2e}") print(f" In MN: {total_force:.2e} MN") print(f" In N: {total_force*1e6:.2e} N") print("\n4. DISPLACEMENT FROM OP2:") print("-"*60) if hasattr(op2, 'displacements') and op2.displacements: for subcase_id, disp in op2.displacements.items(): # Get translation only (DOF 1-3) translations = disp.data[0, :, :3] max_trans = np.max(np.abs(translations)) max_idx = np.unravel_index(np.argmax(np.abs(translations)), translations.shape) print(f" Subcase {subcase_id}:") print(f" Max translation: {max_trans:.6f} mm") print(f" Location: node index {max_idx[0]}, DOF {max_idx[1]}") print("\n5. STRESS FROM OP2 (RAW VALUES):") print("-"*60) # Try new API stress_dict = None if hasattr(op2, 'op2_results') and hasattr(op2.op2_results, 'stress'): if hasattr(op2.op2_results.stress, 'cquad4_stress'): stress_dict = op2.op2_results.stress.cquad4_stress elif hasattr(op2, 'cquad4_stress'): try: stress_dict = op2.cquad4_stress except: pass if stress_dict: for subcase_id, stress in stress_dict.items(): # Stress data columns depend on element type # For CQUAD4: typically [fiber_distance, oxx, oyy, txy, angle, major, minor, von_mises] stress_data = stress.data[0, :, :] print(f" Subcase {subcase_id}:") print(f" Data shape: {stress_data.shape} (elements × stress_components)") print(f" Stress components: {stress_data.shape[1]}") # Von Mises is usually last column von_mises = stress_data[:, -1] print(f"\n Von Mises stress (column {stress_data.shape[1]-1}):") print(f" Min: {np.min(von_mises):.2e}") print(f" Max: {np.max(von_mises):.2e}") print(f" Mean: {np.mean(von_mises):.2e}") print(f" Median: {np.median(von_mises):.2e}") print(f"\n Principal stresses (columns 5-6 typically):") if stress_data.shape[1] >= 7: major = stress_data[:, -3] minor = stress_data[:, -2] print(f" Major max: {np.max(major):.2e}") print(f" Minor min: {np.min(minor):.2e}") print(f"\n Direct stresses (columns 1-2 typically):") if stress_data.shape[1] >= 3: sxx = stress_data[:, 1] syy = stress_data[:, 2] print(f" sigmaxx range: {np.min(sxx):.2e} to {np.max(sxx):.2e}") print(f" sigmayy range: {np.min(syy):.2e} to {np.max(syy):.2e}") print("\n6. REACTIONS FROM OP2:") print("-"*60) if hasattr(op2, 'grid_point_forces') and op2.grid_point_forces: for subcase_id, gpf in op2.grid_point_forces.items(): forces = gpf.data[0] print(f" Subcase {subcase_id}:") print(f" Data shape: {forces.shape}") print(f" Max reaction (all DOF): {np.max(np.abs(forces)):.2e}") # Get force components (first 3 columns usually Fx, Fy, Fz) if forces.shape[1] >= 3: fx = forces[:, 0] fy = forces[:, 1] fz = forces[:, 2] print(f" Fx range: {np.min(fx):.2e} to {np.max(fx):.2e}") print(f" Fy range: {np.min(fy):.2e} to {np.max(fy):.2e}") print(f" Fz range: {np.min(fz):.2e} to {np.max(fz):.2e}") print("\n7. YOUR STATED VALUES:") print("-"*60) print(" You said:") print(" - Stress around 117 MPa") print(" - Force around 152,200 N") print("\n From OP2 raw data above:") print(" - If Von Mises max = 1.17e+05, this is:") print(" -> 117,000 Pa = 117 kPa = 0.117 MPa (if UNITSYS=MN-MM)") print(" -> OR 117,000 MPa (if somehow in MPa already)") print("\n For force 152,200 N:") print(" - If reactions max = 1.52e+08 from OP2:") print(" -> 152,000,000 Pa or N·mm⁻² (if MN-MM system)") print(" -> 152 MN = 152,000,000 N (conversion)") print(" -> OR your expected value is 0.1522 MN = 152,200 N") print("\n8. DIRECTIONS AND TENSORS:") print("-"*60) print(" Stress tensor (symmetric 3×3):") print(" sigma = [sigmaxx tauxy tauxz]") print(" [tauxy sigmayy tauyz]") print(" [tauxz tauyz sigmazz]") print("\n Stored in OP2 for shells (CQUAD4) as:") print(" [fiber_dist, sigmaxx, sigmayy, tauxy, angle, sigma_major, sigma_minor, von_mises]") print("\n Displacement vector (6 DOF per node):") print(" [Tx, Ty, Tz, Rx, Ry, Rz]") print("\n Force/Reaction vector (6 DOF per node):") print(" [Fx, Fy, Fz, Mx, My, Mz]") print("\n" + "="*60)