175 lines
6.4 KiB
Python
175 lines
6.4 KiB
Python
|
|
"""
|
|||
|
|
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)
|