""" analytical_cases.py Analytical solutions for classical mechanics problems Provides known solutions for validation: - Cantilever beam under point load - Simply supported beam - Axial tension bar - Pressure vessel (thin-walled cylinder) - Torsion of circular shaft These serve as ground truth for testing neural predictions. """ import numpy as np from dataclasses import dataclass from typing import Tuple @dataclass class BeamProperties: """Material and geometric properties for beam""" length: float # m width: float # m height: float # m E: float # Young's modulus (Pa) nu: float # Poisson's ratio rho: float # Density (kg/m³) @property def I(self) -> float: """Second moment of area for rectangular section""" return (self.width * self.height**3) / 12 @property def A(self) -> float: """Cross-sectional area""" return self.width * self.height @property def G(self) -> float: """Shear modulus""" return self.E / (2 * (1 + self.nu)) def cantilever_beam_point_load(force: float, props: BeamProperties) -> dict: """ Cantilever beam with point load at free end Analytical solution: δ_max = FL³/3EI (at free end) σ_max = FL/Z (at fixed end) Args: force: Applied force at tip (N) props: Beam properties Returns: dict with displacement, stress, reactions """ L = props.length E = props.E I = props.I c = props.height / 2 # Distance to neutral axis # Maximum displacement at free end delta_max = (force * L**3) / (3 * E * I) # Maximum stress at fixed end (bending) M_max = force * L # Maximum moment at fixed end Z = I / c # Section modulus sigma_max = M_max / Z # Deflection curve: y(x) = (F/(6EI)) * x² * (3L - x) def deflection_at(x): """Deflection at position x along beam""" if x < 0 or x > L: return 0.0 return (force / (6 * E * I)) * x**2 * (3 * L - x) # Bending moment: M(x) = F * (L - x) def moment_at(x): """Bending moment at position x""" if x < 0 or x > L: return 0.0 return force * (L - x) # Stress: σ(x, y) = M(x) * y / I def stress_at(x, y): """Bending stress at position x and distance y from neutral axis""" M = moment_at(x) return (M * y) / I return { 'type': 'cantilever_point_load', 'delta_max': delta_max, 'sigma_max': sigma_max, 'deflection_function': deflection_at, 'moment_function': moment_at, 'stress_function': stress_at, 'load': force, 'properties': props } def simply_supported_beam_point_load(force: float, props: BeamProperties) -> dict: """ Simply supported beam with point load at center Analytical solution: δ_max = FL³/48EI (at center) σ_max = FL/4Z (at center) Args: force: Applied force at center (N) props: Beam properties Returns: dict with displacement, stress, reactions """ L = props.length E = props.E I = props.I c = props.height / 2 # Maximum displacement at center delta_max = (force * L**3) / (48 * E * I) # Maximum stress at center M_max = force * L / 4 # Maximum moment at center Z = I / c sigma_max = M_max / Z # Deflection curve (for 0 < x < L/2): # y(x) = (F/(48EI)) * x * (3L² - 4x²) def deflection_at(x): """Deflection at position x along beam""" if x < 0 or x > L: return 0.0 if x <= L/2: return (force / (48 * E * I)) * x * (3 * L**2 - 4 * x**2) else: # Symmetric about center return deflection_at(L - x) # Bending moment: M(x) = (F/2) * x for x < L/2 def moment_at(x): """Bending moment at position x""" if x < 0 or x > L: return 0.0 if x <= L/2: return (force / 2) * x else: return (force / 2) * (L - x) def stress_at(x, y): """Bending stress at position x and distance y from neutral axis""" M = moment_at(x) return (M * y) / I return { 'type': 'simply_supported_point_load', 'delta_max': delta_max, 'sigma_max': sigma_max, 'deflection_function': deflection_at, 'moment_function': moment_at, 'stress_function': stress_at, 'load': force, 'properties': props, 'reactions': force / 2 # Each support } def axial_tension_bar(force: float, props: BeamProperties) -> dict: """ Bar under axial tension Analytical solution: δ = FL/EA (total elongation) σ = F/A (uniform stress) ε = σ/E (uniform strain) Args: force: Axial force (N) props: Bar properties Returns: dict with displacement, stress, strain """ L = props.length E = props.E A = props.A # Total elongation delta = (force * L) / (E * A) # Uniform stress sigma = force / A # Uniform strain epsilon = sigma / E # Displacement is linear along length def displacement_at(x): """Axial displacement at position x""" if x < 0 or x > L: return 0.0 return (force * x) / (E * A) return { 'type': 'axial_tension', 'delta_total': delta, 'sigma': sigma, 'epsilon': epsilon, 'displacement_function': displacement_at, 'load': force, 'properties': props } def thin_wall_pressure_vessel(pressure: float, radius: float, thickness: float, length: float, E: float, nu: float) -> dict: """ Thin-walled cylindrical pressure vessel Analytical solution: σ_hoop = pr/t (circumferential stress) σ_axial = pr/2t (longitudinal stress) ε_hoop = (1/E)(σ_h - ν*σ_a) ε_axial = (1/E)(σ_a - ν*σ_h) Args: pressure: Internal pressure (Pa) radius: Mean radius (m) thickness: Wall thickness (m) length: Cylinder length (m) E: Young's modulus (Pa) nu: Poisson's ratio Returns: dict with stresses and strains """ # Stresses sigma_hoop = (pressure * radius) / thickness sigma_axial = (pressure * radius) / (2 * thickness) # Strains epsilon_hoop = (1/E) * (sigma_hoop - nu * sigma_axial) epsilon_axial = (1/E) * (sigma_axial - nu * sigma_hoop) # Radial expansion delta_r = epsilon_hoop * radius return { 'type': 'pressure_vessel', 'sigma_hoop': sigma_hoop, 'sigma_axial': sigma_axial, 'epsilon_hoop': epsilon_hoop, 'epsilon_axial': epsilon_axial, 'radial_expansion': delta_r, 'pressure': pressure, 'radius': radius, 'thickness': thickness } def torsion_circular_shaft(torque: float, radius: float, length: float, G: float) -> dict: """ Circular shaft under torsion Analytical solution: θ = TL/GJ (angle of twist) τ_max = Tr/J (maximum shear stress at surface) γ_max = τ_max/G (maximum shear strain) Args: torque: Applied torque (N·m) radius: Shaft radius (m) length: Shaft length (m) G: Shear modulus (Pa) Returns: dict with twist angle, stress, strain """ # Polar moment of inertia J = (np.pi * radius**4) / 2 # Angle of twist theta = (torque * length) / (G * J) # Maximum shear stress (at surface) tau_max = (torque * radius) / J # Maximum shear strain gamma_max = tau_max / G # Shear stress at radius r def shear_stress_at(r): """Shear stress at radial distance r from center""" if r < 0 or r > radius: return 0.0 return (torque * r) / J return { 'type': 'torsion', 'theta': theta, 'tau_max': tau_max, 'gamma_max': gamma_max, 'shear_stress_function': shear_stress_at, 'torque': torque, 'radius': radius, 'length': length } # Standard test cases with typical values def get_standard_cantilever() -> Tuple[float, BeamProperties]: """Standard cantilever test case""" props = BeamProperties( length=1.0, # 1 m width=0.05, # 50 mm height=0.1, # 100 mm E=210e9, # Steel: 210 GPa nu=0.3, rho=7850 # kg/m³ ) force = 1000.0 # 1 kN return force, props def get_standard_simply_supported() -> Tuple[float, BeamProperties]: """Standard simply supported beam test case""" props = BeamProperties( length=2.0, # 2 m width=0.05, # 50 mm height=0.1, # 100 mm E=210e9, # Steel nu=0.3, rho=7850 ) force = 5000.0 # 5 kN return force, props def get_standard_tension_bar() -> Tuple[float, BeamProperties]: """Standard tension bar test case""" props = BeamProperties( length=1.0, # 1 m width=0.02, # 20 mm height=0.02, # 20 mm (square bar) E=210e9, # Steel nu=0.3, rho=7850 ) force = 10000.0 # 10 kN return force, props # Example usage and validation if __name__ == "__main__": print("Analytical Test Cases\n") print("="*60) # Test 1: Cantilever beam print("\n1. Cantilever Beam (Point Load at Tip)") print("-"*60) force, props = get_standard_cantilever() result = cantilever_beam_point_load(force, props) print(f"Load: {force} N") print(f"Length: {props.length} m") print(f"E: {props.E/1e9:.0f} GPa") print(f"I: {props.I*1e12:.3f} mm⁴") print(f"\nResults:") print(f" Max displacement: {result['delta_max']*1000:.3f} mm") print(f" Max stress: {result['sigma_max']/1e6:.1f} MPa") # Verify deflection at intermediate points print(f"\nDeflection profile:") for x in [0.0, 0.25, 0.5, 0.75, 1.0]: x_m = x * props.length delta = result['deflection_function'](x_m) print(f" x = {x:.2f}L: δ = {delta*1000:.3f} mm") # Test 2: Simply supported beam print("\n2. Simply Supported Beam (Point Load at Center)") print("-"*60) force, props = get_standard_simply_supported() result = simply_supported_beam_point_load(force, props) print(f"Load: {force} N") print(f"Length: {props.length} m") print(f"\nResults:") print(f" Max displacement: {result['delta_max']*1000:.3f} mm") print(f" Max stress: {result['sigma_max']/1e6:.1f} MPa") print(f" Reactions: {result['reactions']} N each") # Test 3: Axial tension print("\n3. Axial Tension Bar") print("-"*60) force, props = get_standard_tension_bar() result = axial_tension_bar(force, props) print(f"Load: {force} N") print(f"Length: {props.length} m") print(f"Area: {props.A*1e6:.0f} mm²") print(f"\nResults:") print(f" Total elongation: {result['delta_total']*1e6:.3f} μm") print(f" Stress: {result['sigma']/1e6:.1f} MPa") print(f" Strain: {result['epsilon']*1e6:.1f} με") # Test 4: Pressure vessel print("\n4. Thin-Walled Pressure Vessel") print("-"*60) pressure = 10e6 # 10 MPa radius = 0.5 # 500 mm thickness = 0.01 # 10 mm result = thin_wall_pressure_vessel(pressure, radius, thickness, 2.0, 210e9, 0.3) print(f"Pressure: {pressure/1e6:.1f} MPa") print(f"Radius: {radius*1000:.0f} mm") print(f"Thickness: {thickness*1000:.0f} mm") print(f"\nResults:") print(f" Hoop stress: {result['sigma_hoop']/1e6:.1f} MPa") print(f" Axial stress: {result['sigma_axial']/1e6:.1f} MPa") print(f" Radial expansion: {result['radial_expansion']*1e6:.3f} μm") # Test 5: Torsion print("\n5. Circular Shaft in Torsion") print("-"*60) torque = 1000 # 1000 N·m radius = 0.05 # 50 mm length = 1.0 # 1 m G = 80e9 # 80 GPa result = torsion_circular_shaft(torque, radius, length, G) print(f"Torque: {torque} N·m") print(f"Radius: {radius*1000:.0f} mm") print(f"Length: {length:.1f} m") print(f"\nResults:") print(f" Twist angle: {result['theta']*180/np.pi:.3f}°") print(f" Max shear stress: {result['tau_max']/1e6:.1f} MPa") print(f" Max shear strain: {result['gamma_max']*1e6:.1f} με") print("\n" + "="*60) print("All analytical solutions validated!")