# Structural Analysis

> Structural Analysis Skill

- Skill: `vamseeachanta/structural-analysis` (Agent Skill)
- Install (CLI): `npx skillmds@latest add vamseeachanta/structural-analysis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vamseeachanta/structural-analysis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: vamseeachanta (https://skillmd.com/u/vamseeachanta)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vamseeachanta/structural-analysis

---

# Structural Analysis Skill

```yaml
name: structural-analysis
version: 1.0.0
category: sme
tags: [structural, mechanics, dnv, buckling, uls, als, beam-theory, stress-analysis]
created: 2026-01-06
updated: 2026-01-06
author: Claude
description: |
  Expert structural analysis for marine and offshore structures including
  beam theory, buckling, ULS/ALS limit state checks, and DNV standards.
  Covers tubular members, stiffened panels, and combined loading scenarios.
```

## When to Use This Skill

Use this skill when you need to:
- Perform structural analysis of marine structures
- Check ULS (Ultimate Limit State) and ALS (Accidental Limit State) criteria
- Analyze buckling of columns, beams, and stiffened panels
- Calculate section properties and stress distributions
- Apply DNV structural design standards
- Evaluate combined loading (axial + bending + torsion)
- Design tubular members and jacket structures
- Perform fatigue analysis integration with structural checks

## Core Knowledge Areas

### 1. Beam Theory and Section Properties

Calculate section properties for structural members:

```python
import numpy as np
from dataclasses import dataclass
from typing import Tuple

@dataclass
class SectionProperties:
    """Section properties for structural analysis."""
    area: float  # Cross-sectional area [m²]
    Ix: float  # Second moment of area about x-axis [m⁴]
    Iy: float  # Second moment of area about y-axis [m⁴]
    J: float  # Torsional constant [m⁴]
    Zx: float  # Section modulus about x-axis [m³]
    Zy: float  # Section modulus about y-axis [m³]
    rx: float  # Radius of gyration about x-axis [m]
    ry: float  # Radius of gyration about y-axis [m]

def circular_tube_properties(
    outer_diameter: float,
    wall_thickness: float
) -> SectionProperties:
    """
    Calculate section properties for circular tube.

    Args:
        outer_diameter: Outer diameter [m]
        wall_thickness: Wall thickness [m]

    Returns:
        Section properties

    Example:
        >>> props = circular_tube_properties(D=0.914, t=0.030)
        >>> print(f"Area: {props.area:.4f} m²")
        >>> print(f"Ix: {props.Ix:.6f} m⁴")
    """
    D = outer_diameter
    t = wall_thickness
    d = D - 2 * t  # Inner diameter

    # Cross-sectional area
    A = np.pi / 4 * (D**2 - d**2)

    # Second moments of area (circular symmetry: Ix = Iy)
    I = np.pi / 64 * (D**4 - d**4)

    # Torsional constant (polar moment)
    J = np.pi / 32 * (D**4 - d**4)

    # Section modulus
    Z = I / (D / 2)

    # Radius of gyration
    r = np.sqrt(I / A)

    return SectionProperties(
        area=A,
        Ix=I,
        Iy=I,
        J=J,
        Zx=Z,
        Zy=Z,
        rx=r,
        ry=r
    )

def rectangular_tube_properties(
    width: float,
    height: float,
    wall_thickness: float
) -> SectionProperties:
    """
    Calculate section properties for rectangular hollow section.

    Args:
        width: Outer width [m]
        height: Outer height [m]
        wall_thickness: Wall thickness [m]

    Returns:
        Section properties
    """
    b = width
    h = height
    t = wall_thickness

    # Inner dimensions
    bi = b - 2 * t
    hi = h - 2 * t

    # Cross-sectional area
    A = b * h - bi * hi

    # Second moments of area
    Ix = (b * h**3 - bi * hi**3) / 12
    Iy = (h * b**3 - hi * bi**3) / 12

    # Approximate torsional constant for thin-walled section
    # J ≈ 2·t·(b-t)²·(h-t)² / (b+h-2t) for t << b,h
    J = 2 * t * (b - t)**2 * (h - t)**2 / (b + h - 2 * t)

    # Section moduli
    Zx = 2 * Ix / h
    Zy = 2 * Iy / b

    # Radii of gyration
    rx = np.sqrt(Ix / A)
    ry = np.sqrt(Iy / A)

    return SectionProperties(
        area=A,
        Ix=Ix,
        Iy=Iy,
        J=J,
        Zx=Zx,
        Zy=Zy,
        rx=rx,
        ry=ry
    )

def i_beam_properties(
    flange_width: float,
    web_height: float,
    flange_thickness: float,
    web_thickness: float
) -> SectionProperties:
    """
    Calculate section properties for I-beam/H-beam.

    Args:
        flange_width: Flange width [m]
        web_height: Web height (total height - 2×flange thickness) [m]
        flange_thickness: Flange thickness [m]
        web_thickness: Web thickness [m]

    Returns:
        Section properties
    """
    bf = flange_width
    hw = web_height
    tf = flange_thickness
    tw = web_thickness
    h_total = hw + 2 * tf

    # Cross-sectional area
    A = 2 * bf * tf + hw * tw

    # Second moment about x-axis (strong axis)
    Ix = (bf * h_total**3 - (bf - tw) * hw**3) / 12

    # Second moment about y-axis (weak axis)
    Iy = (2 * tf * bf**3 + hw * tw**3) / 12

    # Approximate torsional constant
    # J ≈ Σ(b·t³/3) for thin-walled open sections
    J = (2 * bf * tf**3 + hw * tw**3) / 3

    # Section moduli
    Zx = 2 * Ix / h_total
    Zy = 2 * Iy / bf

    # Radii of gyration
    rx = np.sqrt(Ix / A)
    ry = np.sqrt(Iy / A)

    return SectionProperties(
        area=A,
        Ix=Ix,
        Iy=Iy,
        J=J,
        Zx=Zx,
        Zy=Zy,
        rx=rx,
        ry=ry
    )
```

### 2. Stress Analysis

Calculate stresses under combined loading:

```python
@dataclass
class LoadCase:
    """Loading case for structural member."""
    axial_force: float  # Axial force [N] (tension positive)
    bending_moment_x: float  # Bending moment about x-axis [N·m]
    bending_moment_y: float  # Bending moment about y-axis [N·m]
    shear_force_x: float  # Shear force in x-direction [N]
    shear_force_y: float  # Shear force in y-direction [N]
    torsional_moment: float  # Torsional moment [N·m]

def calculate_stresses(
    load: LoadCase,
    section: SectionProperties,
    distance_x: float = None,
    distance_y: float = None
) -> dict:
    """
    Calculate stresses at a point in the cross-section.

    Args:
        load: Load case
        section: Section properties
        distance_x: Distance from neutral axis in x-direction [m]
        distance_y: Distance from neutral axis in y-direction [m]

    Returns:
        Dictionary with stress components [Pa]

    Example:
        >>> load = LoadCase(
        ...     axial_force=1000e3,
        ...     bending_moment_x=500e3,
        ...     bending_moment_y=0,
        ...     shear_force_x=0,
        ...     shear_force_y=100e3,
        ...     torsional_moment=50e3
        ... )
        >>> section = circular_tube_properties(0.914, 0.030)
        >>> stresses = calculate_stresses(load, section, 0, 0.457)
        >>> print(f"Axial stress: {stresses['axial']/1e6:.1f} MPa")
    """
    # Axial stress: σ_axial = N/A
    sigma_axial = load.axial_force / section.area

    # Bending stress: σ_bending = M·y/I
    if distance_y is not None:
        sigma_bending_x = load.bending_moment_x * distance_y / section.Ix
    else:
        # Maximum bending stress at extreme fiber
        sigma_bending_x = abs(load.bending_moment_x) / section.Zx

    if distance_x is not None:
        sigma_bending_y = load.bending_moment_y * distance_x / section.Iy
    else:
        sigma_bending_y = abs(load.bending_moment_y) / section.Zy

    # Total normal stress
    sigma_total = sigma_axial + sigma_bending_x + sigma_bending_y

    # Shear stress from torsion: τ = T·r/J
    if distance_x is not None and distance_y is not None:
        r = np.sqrt(distance_x**2 + distance_y**2)
        tau_torsion = load.torsional_moment * r / section.J
    else:
        # Maximum torsional shear stress at outer fiber
        # For circular tube: r = D/2
        # Approximate for other sections
        tau_torsion = load.torsional_moment / (section.J / np.sqrt(section.rx**2 + section.ry**2))

    # Shear stress from transverse loads (approximate)
    # For rectangular sections: τ_avg = V/A
    tau_shear_x = load.shear_force_x / section.area
    tau_shear_y = load.shear_force_y / section.area

    # Total shear stress (vectorial sum)
    tau_total = np.sqrt((tau_torsion + tau_shear_x)**2 + tau_shear_y**2)

    # Von Mises equivalent stress
    sigma_vm = np.sqrt(sigma_total**2 + 3 * tau_total**2)

    return {
        'axial': sigma_axial,
        'bending_x': sigma_bending_x,
        'bending_y': sigma_bending_y,
        'normal_total': sigma_total,
        'shear_torsion': tau_torsion,
        'shear_transverse_x': tau_shear_x,
        'shear_transverse_y': tau_shear_y,
        'shear_total': tau_total,
        'von_mises': sigma_vm
    }

def calculate_principal_stresses(
    sigma_x: float,
    sigma_y: float,
    tau_xy: float
) -> Tuple[float, float, float]:
    """
    Calculate principal stresses and maximum shear stress.

    Args:
        sigma_x: Normal stress in x-direction [Pa]
        sigma_y: Normal stress in y-direction [Pa]
        tau_xy: Shear stress [Pa]

    Returns:
        Tuple of (sigma_1, sigma_2, tau_max) [Pa]

    Example:
        >>> sigma_1, sigma_2, tau_max = calculate_principal_stresses(
        ...     sigma_x=100e6, sigma_y=-50e6, tau_xy=30e6
        ... )
        >>> print(f"σ₁ = {sigma_1/1e6:.1f} MPa")
        >>> print(f"σ₂ = {sigma_2/1e6:.1f} MPa")
        >>> print(f"τ_max = {tau_max/1e6:.1f} MPa")
    """
    # Center of Mohr's circle
    sigma_avg = (sigma_x + sigma_y) / 2

    # Radius of Mohr's circle
    R = np.sqrt(((sigma_x - sigma_y) / 2)**2 + tau_xy**2)

    # Principal stresses
    sigma_1 = sigma_avg + R  # Maximum principal stress
    sigma_2 = sigma_avg - R  # Minimum principal stress

    # Maximum shear stress
    tau_max = R

    return sigma_1, sigma_2, tau_max
```

### 3. Column Buckling Analysis

Euler buckling and DNV buckling checks:

```python
def euler_buckling_load(
    E: float,
    I: float,
    L: float,
    K: float = 1.0
) -> float:
    """
    Calculate Euler critical buckling load.

    Args:
        E: Young's modulus [Pa]
        I: Second moment of area [m⁴]
        L: Column length [m]
        K: Effective length factor (1.0 = pinned-pinned)
            K = 0.5 (fixed-fixed)
            K = 0.7 (fixed-pinned)
            K = 1.0 (pinned-pinned)
            K = 2.0 (fixed-free)

    Returns:
        Critical buckling load [N]

    Example:
        >>> E_steel = 210e9  # Pa
        >>> section = circular_tube_properties(0.914, 0.030)
        >>> L = 30.0  # m
        >>> P_cr = euler_buckling_load(E_steel, section.Ix, L, K=1.0)
        >>> print(f"Critical load: {P_cr/1e6:.1f} MN")
    """
    # Effective length
    Le = K * L

    # Euler critical load: P_cr = π²EI/Le²
    P_cr = np.pi**2 * E * I / Le**2

    return P_cr

def slenderness_ratio(
    L: float,
    r: float,
    K: float = 1.0
) -> float:
    """
    Calculate slenderness ratio.

    Args:
        L: Column length [m]
        r: Radius of gyration [m]
        K: Effective length factor

    Returns:
        Slenderness ratio λ (dimensionless)
    """
    Le = K * L
    lambda_ratio = Le / r
    return lambda_ratio

def dnv_column_buckling_check(
    axial_force: float,
    E: float,
    fy: float,
    A: float,
    I: float,
    L: float,
    K: float = 1.0,
    gamma_M: float = 1.15
) -> dict:
    """
    DNV column buckling check (DNV-OS-C101, DNV-RP-C201).

    Args:
        axial_force: Applied axial force [N] (compression positive)
        E: Young's modulus [Pa]
        fy: Yield strength [Pa]
        A: Cross-sectional area [m²]
        I: Second moment of area [m⁴]
        L: Column length [m]
        K: Effective length factor
        gamma_M: Material safety factor (1.15 for ULS)

    Returns:
        Dictionary with buckling check results

    Example:
        >>> result = dnv_column_buckling_check(
        ...     axial_force=5000e3,
        ...     E=210e9,
        ...     fy=355e6,
        ...     A=0.082,
        ...     I=0.0135,
        ...     L=30.0,
        ...     K=1.0
        ... )
        >>> print(f"Unity check: {result['unity_check']:.3f}")
        >>> print(f"Status: {result['status']}")
    """
    Le = K * L
    r = np.sqrt(I / A)
    lambda_ratio = Le / r

    # Reduced slenderness ratio
    lambda_bar = lambda_ratio * np.sqrt(fy / E) / np.pi

    # Buckling reduction factor (European column curves)
    # Using curve 'a' for welded tubular sections
    alpha = 0.21  # Imperfection factor for curve 'a'
    phi = 0.5 * (1 + alpha * (lambda_bar - 0.2) + lambda_bar**2)
    chi = min(1.0, 1 / (phi + np.sqrt(phi**2 - lambda_bar**2)))

    # Design buckling resistance
    N_b_Rd = chi * A * fy / gamma_M

    # Unity check
    unity_check = axial_force / N_b_Rd

    # Critical buckling load (Euler)
    P_cr = np.pi**2 * E * I / Le**2

    status = "PASS" if unity_check <= 1.0 else "FAIL"

    return {
        'slenderness_ratio': lambda_ratio,
        'reduced_slenderness': lambda_bar,
        'buckling_reduction_factor': chi,
        'design_resistance': N_b_Rd,
        'applied_force': axial_force,
        'unity_check': unity_check,
        'critical_load_euler': P_cr,
        'status': status
    }
```

### 4. Beam Bending and Deflection

```python
def simply_supported_beam_deflection(
    load_type: str,
    E: float,
    I: float,
    L: float,
    load_magnitude: float,
    x: float = None
) -> dict:
    """
    Calculate deflection for simply supported beam.

    Args:
        load_type: 'point_center', 'uniform', 'point_arbitrary'
        E: Young's modulus [Pa]
        I: Second moment of area [m⁴]
        L: Beam length [m]
        load_magnitude: Load magnitude [N] or [N/m]
        x: Position along beam [m] (for arbitrary point load)

    Returns:
        Dictionary with max deflection and location

    Example:
        >>> result = simply_supported_beam_deflection(
        ...     load_type='uniform',
        ...     E=210e9,
        ...     I=0.0135,
        ...     L=30.0,
        ...     load_magnitude=10e3  # 10 kN/m
        ... )
        >>> print(f"Max deflection: {result['max_deflection']*1000:.1f} mm")
    """
    if load_type == 'point_center':
        # Point load at center: δ_max = PL³/(48EI)
        P = load_magnitude
        delta_max = P * L**3 / (48 * E * I)
        x_max = L / 2

    elif load_type == 'uniform':
        # Uniformly distributed load: δ_max = 5wL⁴/(384EI)
        w = load_magnitude
        delta_max = 5 * w * L**4 / (384 * E * I)
        x_max = L / 2

    elif load_type == 'point_arbitrary' and x is not None:
        # Point load at distance 'a' from left support
        # δ_max at x = sqrt(L² - a²)/sqrt(3) (approximate)
        P = load_magnitude
        a = x
        b = L - a
        # Maximum deflection (at x position)
        delta_at_a = P * a**2 * b**2 / (3 * E * I * L)
        delta_max = delta_at_a
        x_max = a
    else:
        raise ValueError(f"Unknown load_type: {load_type}")

    # Allowable deflection (L/360 for general structures)
    delta_allowable = L / 360

    unity_check = delta_max / delta_allowable
    status = "PASS" if unity_check <= 1.0 else "FAIL"

    return {
        'max_deflection': delta_max,
        'location': x_max,
        'allowable_deflection': delta_allowable,
        'unity_check': unity_check,
        'status': status
    }

def cantilever_beam_deflection(
    load_type: str,
    E: float,
    I: float,
    L: float,
    load_magnitude: float
) -> dict:
    """
    Calculate deflection for cantilever beam (fixed at one end).

    Args:
        load_type: 'point_end', 'uniform'
        E: Young's modulus [Pa]
        I: Second moment of area [m⁴]
        L: Beam length [m]
        load_magnitude: Load magnitude [N] or [N/m]

    Returns:
        Dictionary with max deflection
    """
    if load_type == 'point_end':
        # Point load at free end: δ_max = PL³/(3EI)
        P = load_magnitude
        delta_max = P * L**3 / (3 * E * I)

    elif load_type == 'uniform':
        # Uniformly distributed load: δ_max = wL⁴/(8EI)
        w = load_magnitude
        delta_max = w * L**4 / (8 * E * I)
    else:
        raise ValueError(f"Unknown load_type: {load_type}")

    # Allowable deflection (L/180 for cantilever)
    delta_allowable = L / 180

    unity_check = delta_max / delta_allowable
    status = "PASS" if unity_check <= 1.0 else "FAIL"

    return {
        'max_deflection': delta_max,
        'allowable_deflection': delta_allowable,
        'unity_check': unity_check,
        'status': status
    }
```

### 5. Tubular Joint Design (DNV)

```python
def tubular_joint_capacity_check(
    chord_diameter: float,
    chord_thickness: float,
    brace_diameter: float,
    brace_thickness: float,
    brace_angle: float,
    fy_chord: float,
    fy_brace: float,
    axial_load: float = 0,
    in_plane_bending: float = 0,
    out_plane_bending: float = 0,
    joint_type: str = 'T'
) -> dict:
    """
    Tubular joint capacity check per DNV-RP-C203.

    Args:
        chord_diameter: Chord outer diameter [m]
        chord_thickness: Chord wall thickness [m]
        brace_diameter: Brace outer diameter [m]
        brace_thickness: Brace wall thickness [m]
        brace_angle: Angle between brace and chord [degrees]
        fy_chord: Chord yield strength [Pa]
        fy_brace: Brace yield strength [Pa]
        axial_load: Axial load in brace [N]
        in_plane_bending: In-plane bending moment [N·m]
        out_plane_bending: Out-of-plane bending moment [N·m]
        joint_type: 'T', 'Y', 'K', 'X'

    Returns:
        Dictionary with joint capacity check

    Example:
        >>> result = tubular_joint_capacity_check(
        ...     chord_diameter=1.5,
        ...     chord_thickness=0.050,
        ...     brace_diameter=0.914,
        ...     brace_thickness=0.030,
        ...     brace_angle=90,
        ...     fy_chord=355e6,
        ...     fy_brace=355e6,
        ...     axial_load=2000e3,
        ...     in_plane_bending=500e3,
        ...     out_plane_bending=0,
        ...     joint_type='T'
        ... )
        >>> print(f"Unity check: {result['unity_check']:.3f}")
    """
    D = chord_diameter
    T = chord_thickness
    d = brace_diameter
    t = brace_thickness
    theta = np.radians(brace_angle)

    # Geometric parameters
    beta = d / D  # Diameter ratio
    gamma = D / (2 * T)  # Chord slenderness
    tau = t / T  # Thickness ratio

    # Validity range checks
    validity_checks = {
        'beta_range': 0.2 <= beta <= 1.0,
        'gamma_range': 10 <= gamma <= 50,
        'theta_range': np.degrees(theta) >= 30
    }

    if not all(validity_checks.values()):
        warnings = [k for k, v in validity_checks.items() if not v]
        print(f"Warning: Out of validity range: {warnings}")

    # Chord stress function (simplified - depends on chord loading)
    # Typically need to account for chord utilization
    Qf = 1.0  # Assume no chord pre-stress for simplicity

    # Strength function depends on joint type and loading
    if joint_type == 'T' or joint_type == 'Y':
        # Axial capacity
        if axial_load >= 0:  # Tension
            # Tension capacity
            Qu = 5.2 * gamma**(-0.2) * beta**0.5 * (1 + beta)**(-0.9) * Qf
        else:  # Compression
            # Compression capacity (punching shear)
            Qu = (2.8 + 14.2 * beta**2) * gamma**(-0.9) * Qf / np.sin(theta)

        # Nominal capacity
        N_capacity = Qu * fy_chord * T**2 / np.sin(theta)

        # In-plane bending capacity
        Qf_ipb = 1.3 * gamma**(-0.4) * beta**0.2 * Qf
        M_ipb_capacity = Qf_ipb * fy_chord * T**2 * d / np.sin(theta)

        # Out-of-plane bending capacity
        Qf_opb = 1.3 * gamma**(-0.4) * beta**0.2 * Qf
        M_opb_capacity = Qf_opb * fy_chord * T**2 * d

    else:
        raise NotImplementedError(f"Joint type {joint_type} not implemented")

    # Interaction check
    # DNV uses: (N/N_cap)^p + (M_ipb/M_ipb_cap)^p + (M_opb/M_opb_cap)^p ≤ 1
    # where p typically = 1.0 or 2.0
    p = 2.0

    unity_check = (
        (abs(axial_load) / N_capacity)**p +
        (abs(in_plane_bending) / M_ipb_capacity)**p +
        (abs(out_plane_bending) / M_opb_capacity)**p
    )**(1/p)

    status = "PASS" if unity_check <= 1.0 else "FAIL"

    return {
        'beta': beta,
        'gamma': gamma,
        'tau': tau,
        'axial_capacity': N_capacity,
        'ipb_capacity': M_ipb_capacity,
        'opb_capacity': M_opb_capacity,
        'applied_axial': axial_load,
        'applied_ipb': in_plane_bending,
        'applied_opb': out_plane_bending,
        'unity_check': unity_check,
        'status': status,
        'validity_checks': validity_checks
    }
```

### 6. ULS and ALS Limit State Checks

```python
def uls_combined_loading_check(
    axial_force: float,
    bending_moment_y: float,
    bending_moment_z: float,
    fy: float,
    section: SectionProperties,
    gamma_M: float = 1.15,
    load_factors: dict = None
) -> dict:
    """
    Ultimate Limit State (ULS) check for combined loading per DNV.

    Args:
        axial_force: Axial force [N] (tension positive)
        bending_moment_y: Bending moment about y-axis [N·m]
        bending_moment_z: Bending moment about z-axis [N·m]
        fy: Yield strength [Pa]
        section: Section properties
        gamma_M: Material safety factor (1.15 for ULS)
        load_factors: Dictionary with partial safety factors

    Returns:
        Dictionary with ULS check results

    Example:
        >>> section = circular_tube_properties(0.914, 0.030)
        >>> result = uls_combined_loading_check(
        ...     axial_force=-5000e3,  # Compression
        ...     bending_moment_y=1200e3,
        ...     bending_moment_z=0,
        ...     fy=355e6,
        ...     section=section
        ... )
        >>> print(f"Unity check: {result['unity_check']:.3f}")
    """
    if load_factors is None:
        # Default DNV load factors for ULS
        load_factors = {
            'axial': 1.3,
            'bending': 1.3
        }

    # Apply load factors
    Sd_axial = abs(axial_force) * load_factors['axial']
    Sd_My = abs(bending_moment_y) * load_factors['bending']
    Sd_Mz = abs(bending_moment_z) * load_factors['bending']

    # Design resistances
    N_Rd = section.area * fy / gamma_M
    My_Rd = section.Zy * fy / gamma_M
    Mz_Rd = section.Zx * fy / gamma_M

    # Interaction check (DNV-OS-C101)
    # For members with axial force and bending:
    # N/N_Rd + My/My_Rd + Mz/Mz_Rd ≤ 1.0 (conservative linear interaction)
    # More accurate: (N/N_Rd)^α + (My/My_Rd + Mz/Mz_Rd)^β ≤ 1.0

    # Conservative linear interaction
    unity_check_linear = (
        Sd_axial / N_Rd +
        Sd_My / My_Rd +
        Sd_Mz / Mz_Rd
    )

    # Eurocode interaction formula (more accurate)
    # For Class 1 and 2 cross-sections
    alpha = 2.0
    beta = 1.0
    unity_check_eurocode = (Sd_axial / N_Rd)**alpha + (
        (Sd_My / My_Rd + Sd_Mz / Mz_Rd)**beta
    )

    # Use conservative check
    unity_check = max(unity_check_linear, unity_check_eurocode)

    status = "PASS" if unity_check <= 1.0 else "FAIL"

    # Calculate utilization ratios
    utilization = {
        'axial': Sd_axial / N_Rd,
        'bending_y': Sd_My / My_Rd,
        'bending_z': Sd_Mz / Mz_Rd
    }

    return {
        'design_axial_force': Sd_axial,
        'design_moment_y': Sd_My,
        'design_moment_z': Sd_Mz,
        'axial_resistance': N_Rd,
        'moment_resistance_y': My_Rd,
        'moment_resistance_z': Mz_Rd,
        'unity_check_linear': unity_check_linear,
        'unity_check_eurocode': unity_check_eurocode,
        'unity_check': unity_check,
        'utilization': utilization,
        'status': status
    }

def als_dented_pipe_check(
    D: float,
    t: float,
    dent_depth: float,
    internal_pressure: float,
    fy: float,
    safety_factor: float = 1.0
) -> dict:
    """
    Accidental Limit State (ALS) check for dented pipe per DNV-RP-F110.

    Args:
        D: Outer diameter [m]
        t: Wall thickness [m]
        dent_depth: Dent depth [m]
        internal_pressure: Internal pressure [Pa]
        fy: Yield strength [Pa]
        safety_factor: Safety factor for ALS (typically 1.0)

    Returns:
        Dictionary with ALS check for dented pipe

    Example:
        >>> result = als_dented_pipe_check(
        ...     D=0.660,
        ...     t=0.020,
        ...     dent_depth=0.030,
        ...     internal_pressure=15e6,
        ...     fy=450e6
        ... )
        >>> print(f"Status: {result['status']}")
    """
    # Dent depth ratio
    delta_ratio = dent_depth / D

    # DNV acceptance criteria for dented pipes
    # For dent depth < 6% D: acceptable for continued operation
    # For 6% < dent depth < 20% D: engineering assessment required
    # For dent depth > 20% D: repair or replacement required

    if delta_ratio < 0.06:
        category = "Acceptable"
    elif delta_ratio < 0.20:
        category = "Engineering Assessment Required"
    else:
        category = "Repair/Replacement Required"

    # Burst pressure reduction factor due to dent
    # Simplified model: reduction proportional to dent depth
    f_dent = max(0, 1 - 5 * delta_ratio)

    # Burst pressure (Barlow's formula with reduction)
    # P_burst = 2·t·fy / D
    P_burst_intact = 2 * t * fy / D
    P_burst_dented = f_dent * P_burst_intact

    # Design pressure
    P_design = internal_pressure * safety_factor

    # Unity check
    unity_check = P_design / P_burst_dented if P_burst_dented > 0 else float('inf')

    status = "PASS" if unity_check <= 1.0 else "FAIL"

    return {
        'dent_depth_ratio': delta_ratio,
        'category': category,
        'burst_pressure_intact': P_burst_intact,
        'burst_pressure_dented': P_burst_dented,
        'design_pressure': P_design,
        'reduction_factor': f_dent,
        'unity_check': unity_check,
        'status': status
    }
```

## Complete Examples

### Example 1: Tubular Member Design for Jacket Structure

```python
import numpy as np

def design_jacket_leg(
    water_depth: float,
    environmental_load: dict,
    material: dict,
    safety_factors: dict
) -> dict:
    """
    Complete design of jacket leg tubular member.

    Args:
        water_depth: Water depth [m]
        environmental_load: Environmental loading
        material: Material properties
        safety_factors: Safety factors for design

    Returns:
        Design results with all checks

    Example:
        >>> environmental_load = {
        ...     'wave_force': 1500e3,  # N
        ...     'current_force': 300e3,
        ...     'wind_force': 200e3,
        ...     'bending_moment': 50e6  # N·m
        ... }
        >>> material = {
        ...     'E': 210e9,  # Pa
        ...     'fy': 355e6,
        ...     'density': 7850  # kg/m³
        ... }
        >>> safety_factors = {
        ...     'gamma_F': 1.35,  # Load factor
        ...     'gamma_M': 1.15   # Material factor
        ... }
        >>> result = design_jacket_leg(
        ...     water_depth=100,
        ...     environmental_load=environmental_load,
        ...     material=material,
        ...     safety_factors=safety_factors
        ... )
        >>> print(f"Required diameter: {result['diameter']:.3f} m")
        >>> print(f"Wall thickness: {result['thickness']*1000:.1f} mm")
    """
    # Initial sizing based on experience
    # For jacket legs: D typically 0.8-2.0 m, t typically 20-80 mm
    D = 1.5  # m
    t = 0.050  # m

    # Calculate section properties
    section = circular_tube_properties(D, t)

    # Length of member (assume from seabed to mean water level + freeboard)
    L = water_depth + 15  # m (15 m freeboard)

    # Combined loading
    # Axial force (self-weight + buoyancy + vertical environmental)
    # Estimate self-weight
    volume = section.area * L
    weight = volume * material['density'] * 9.81

    # Buoyancy (submerged length)
    rho_water = 1025  # kg/m³
    volume_submerged = section.area * water_depth
    buoyancy = volume_submerged * rho_water * 9.81

    # Net axial force (compression from self-weight, reduced by buoyancy)
    axial_force = weight - buoyancy

    # Add environmental axial component (compression from topside weight)
    topside_reaction = 5000e3  # N (example)
    axial_force += topside_reaction

    # Bending moment from lateral loads
    bending_moment = environmental_load['bending_moment']

    # Apply load factors
    Sd_axial = axial_force * safety_factors['gamma_F']
    Sd_moment = bending_moment * safety_factors['gamma_F']

    # 1. ULS Combined Loading Check
    uls_result = uls_combined_loading_check(
        axial_force=-Sd_axial,  # Compression
        bending_moment_y=Sd_moment,
        bending_moment_z=0,
        fy=material['fy'],
        section=section,
        gamma_M=safety_factors['gamma_M']
    )

    # 2. Buckling Check
    buckling_result = dnv_column_buckling_check(
        axial_force=Sd_axial,
        E=material['E'],
        fy=material['fy'],
        A=section.area,
        I=section.Ix,
        L=L,
        K=1.0,  # Pinned-pinned assumption
        gamma_M=safety_factors['gamma_M']
    )

    # 3. Deflection Check (serviceability)
    # Lateral load
    lateral_load = (
        environmental_load['wave_force'] +
        environmental_load['current_force'] +
        environmental_load['wind_force']
    )

    deflection_result = cantilever_beam_deflection(
        load_type='point_end',
        E=material['E'],
        I=section.Ix,
        L=L,
        load_magnitude=lateral_load
    )

    # Overall design check
    all_checks_pass = (
        uls_result['status'] == 'PASS' and
        buckling_result['status'] == 'PASS' and
        deflection_result['status'] == 'PASS'
    )

    return {
        'diameter': D,
        'thickness': t,
        'length': L,
        'section_properties': section,
        'loads': {
            'axial_design': Sd_axial,
            'moment_design': Sd_moment,
            'lateral_load': lateral_load
        },
        'uls_check': uls_result,
        'buckling_check': buckling_result,
        'deflection_check': deflection_result,
        'overall_status': 'PASS' if all_checks_pass else 'FAIL',
        'critical_unity_check': max(
            uls_result['unity_check'],
            buckling_result['unity_check'],
            deflection_result['unity_check']
        )
    }

# Run design
environmental_load = {
    'wave_force': 1500e3,
    'current_force': 300e3,
    'wind_force': 200e3,
    'bending_moment': 50e6
}

material = {
    'E': 210e9,
    'fy': 355e6,
    'density': 7850
}

safety_factors = {
    'gamma_F': 1.35,
    'gamma_M': 1.15
}

design_result = design_jacket_leg(
    water_depth=100,
    environmental_load=environmental_load,
    material=material,
    safety_factors=safety_factors
)

print("=" * 70)
print("JACKET LEG DESIGN SUMMARY")
print("=" * 70)
print(f"Diameter: {design_result['diameter']:.3f} m")
print(f"Wall Thickness: {design_result['thickness']*1000:.1f} mm")
print(f"Length: {design_result['length']:.1f} m")
print(f"\nSection Properties:")
print(f"  Area: {design_result['section_properties'].area:.4f} m²")
print(f"  Ix: {design_result['section_properties'].Ix:.6f} m⁴")
print(f"\nDesign Loads:")
print(f"  Axial (design): {design_result['loads']['axial_design']/1e6:.1f} MN")
print(f"  Moment (design): {design_result['loads']['moment_design']/1e6:.1f} MN·m")
print(f"\nULS Check: {design_result['uls_check']['status']}")
print(f"  Unity Check: {design_result['uls_check']['unity_check']:.3f}")
print(f"\nBuckling Check: {design_result['buckling_check']['status']}")
print(f"  Unity Check: {design_result['buckling_check']['unity_check']:.3f}")
print(f"  Slenderness Ratio: {design_result['buckling_check']['slenderness_ratio']:.1f}")
print(f"\nDeflection Check: {design_result['deflection_check']['status']}")
print(f"  Max Deflection: {design_result['deflection_check']['max_deflection']*1000:.1f} mm")
print(f"  Allowable: {design_result['deflection_check']['allowable_deflection']*1000:.1f} mm")
print(f"\n{'='*70}")
print(f"OVERALL DESIGN STATUS: {design_result['overall_status']}")
print(f"Critical Unity Check: {design_result['critical_unity_check']:.3f}")
print(f"{'='*70}")
```

### Example 2: Tubular Joint Analysis

```python
def analyze_tubular_joint_with_fatigue(
    chord_diameter: float,
    chord_thickness: float,
    brace_diameter: float,
    brace_thickness: float,
    brace_angle: float,
    static_loads: dict,
    cyclic_loads: dict,
    material: dict,
    design_life: float = 25.0
) -> dict:
    """
    Complete tubular joint analysis including static and fatigue checks.

    Args:
        chord_diameter: Chord OD [m]
        chord_thickness: Chord wall thickness [m]
        brace_diameter: Brace OD [m]
        brace_thickness: Brace wall thickness [m]
        brace_angle: Angle [degrees]
        static_loads: Static loading
        cyclic_loads: Cyclic loading for fatigue
        material: Material properties
        design_life: Design life [years]

    Returns:
        Complete analysis results

    Example:
        >>> static_loads = {
        ...     'axial': 2500e3,
        ...     'ipb': 800e3,
        ...     'opb': 0
        ... }
        >>> cyclic_loads = {
        ...     'stress_range': 80e6,  # Pa
        ...     'cycles_per_year': 1e6
        ... }
        >>> material = {
        ...     'fy_chord': 355e6,
        ...     'fy_brace': 355e6,
        ...     'sn_curve': 'D'
        ... }
        >>> result = analyze_tubular_joint_with_fatigue(
        ...     chord_diameter=1.5,
        ...     chord_thickness=0.050,
        ...     brace_diameter=0.914,
        ...     brace_thickness=0.030,
        ...     brace_angle=45,
        ...     static_loads=static_loads,
        ...     cyclic_loads=cyclic_loads,
        ...     material=material,
        ...     design_life=25.0
        ... )
        >>> print(f"Static UC: {result['static_check']['unity_check']:.3f}")
        >>> print(f"Fatigue Life: {result['fatigue_life']:.1f} years")
    """
    # Static capacity check
    static_check = tubular_joint_capacity_check(
        chord_diameter=chord_diameter,
        chord_thickness=chord_thickness,
        brace_diameter=brace_diameter,
        brace_thickness=brace_thickness,
        brace_angle=brace_angle,
        fy_chord=material['fy_chord'],
        fy_brace=material['fy_brace'],
        axial_load=static_loads['axial'],
        in_plane_bending=static_loads['ipb'],
        out_plane_bending=static_loads['opb'],
        joint_type='Y'
    )

    # Fatigue analysis
    # Get S-N curve (using same function as fatigue-analysis skill)
    from fatigue_analysis import get_dnv_sn_curve, calculate_fatigue_damage

    sn_params = get_dnv_sn_curve(
        curve_class=material['sn_curve'],
        thickness=chord_thickness * 1000  # Convert to mm
    )

    # Total cycles over design life
    N_total = cyclic_loads['cycles_per_year'] * design_life

    # Fatigue damage
    stress_range = cyclic_loads['stress_range']
    damage = calculate_fatigue_damage(
        stress_range=stress_range / 1e6,  # Convert to MPa
        cycles=N_total,
        sn_params=sn_params
    )

    # Fatigue life
    if damage > 0:
        fatigue_life = design_life / damage
    else:
        fatigue_life = float('inf')

    fatigue_status = "PASS" if damage <= 1.0 else "FAIL"

    # Hot spot stress concentration factor (SCF) for tubular joints
    # Simplified - actual SCF depends on joint geometry and load type
    beta = brace_diameter / chord_diameter
    gamma = chord_diameter / (2 * chord_thickness)
    tau = brace_thickness / chord_thickness

    # Axial SCF (simplified Efthymiou equations)
    SCF_axial = gamma**0.2 * beta**(-0.5) * (1.2 + 0.1 * beta)

    # Combined hot spot stress
    hot_spot_stress = SCF_axial * stress_range

    return {
        'static_check': static_check,
        'fatigue_damage': damage,
        'fatigue_life': fatigue_life,
        'fatigue_status': fatigue_status,
        'scf': {
            'axial': SCF_axial,
            'hot_spot_stress': hot_spot_stress
        },
        'joint_parameters': {
            'beta': beta,
            'gamma': gamma,
            'tau': tau
        },
        'overall_status': (
            'PASS' if static_check['status'] == 'PASS' and fatigue_status == 'PASS'
            else 'FAIL'
        )
    }

# Run analysis
static_loads = {
    'axial': 2500e3,
    'ipb': 800e3,
    'opb': 0
}

cyclic_loads = {
    'stress_range': 80e6,
    'cycles_per_year': 1e6
}

material = {
    'fy_chord': 355e6,
    'fy_brace': 355e6,
    'sn_curve': 'D'
}

joint_result = analyze_tubular_joint_with_fatigue(
    chord_diameter=1.5,
    chord_thickness=0.050,
    brace_diameter=0.914,
    brace_thickness=0.030,
    brace_angle=45,
    static_loads=static_loads,
    cyclic_loads=cyclic_loads,
    material=material,
    design_life=25.0
)

print("=" * 70)
print("TUBULAR JOINT ANALYSIS")
print("=" * 70)
print(f"\nStatic Capacity Check: {joint_result['static_check']['status']}")
print(f"  Unity Check: {joint_result['static_check']['unity_check']:.3f}")
print(f"  Axial Capacity: {joint_result['static_check']['axial_capacity']/1e6:.1f} MN")
print(f"  Applied Axial: {joint_result['static_check']['applied_axial']/1e6:.1f} MN")
print(f"\nFatigue Analysis: {joint_result['fatigue_status']}")
print(f"  Fatigue Damage: {joint_result['fatigue_damage']:.3f}")
print(f"  Fatigue Life: {joint_result['fatigue_life']:.1f} years")
print(f"\nStress Concentration:")
print(f"  SCF (axial): {joint_result['scf']['axial']:.2f}")
print(f"  Hot Spot Stress: {joint_result['scf']['hot_spot_stress']/1e6:.1f} MPa")
print(f"\n{'='*70}")
print(f"OVERALL STATUS: {joint_result['overall_status']}")
print(f"{'='*70}")
```

### Example 3: Stiffened Panel Buckling

```python
def stiffened_panel_buckling_analysis(
    plate_width: float,
    plate_length: float,
    plate_thickness: float,
    stiffener_spacing: float,
    stiffener_height: float,
    stiffener_thickness: float,
    applied_stress: float,
    E: float = 210e9,
    nu: float = 0.3,
    fy: float = 355e6
) -> dict:
    """
    Buckling analysis for stiffened panel (ship hull, deck, etc.).

    Args:
        plate_width: Panel width (between supports) [m]
        plate_length: Panel length [m]
        plate_thickness: Plate thickness [m]
        stiffener_spacing: Spacing between stiffeners [m]
        stiffener_height: Stiffener web height [m]
        stiffener_thickness: Stiffener web thickness [m]
        applied_stress: Applied compressive stress [Pa]
        E: Young's modulus [Pa]
        nu: Poisson's ratio
        fy: Yield strength [Pa]

    Returns:
        Buckling analysis results

    Example:
        >>> result = stiffened_panel_buckling_analysis(
        ...     plate_width=4.0,
        ...     plate_length=12.0,
        ...     plate_thickness=0.012,
        ...     stiffener_spacing=0.8,
        ...     stiffener_height=0.200,
        ...     stiffener_thickness=0.010,
        ...     applied_stress=150e6,
        ...     E=210e9,
        ...     fy=355e6
        ... )
        >>> print(f"Panel buckling UC: {result['panel_buckling_uc']:.3f}")
        >>> print(f"Column buckling UC: {result['column_buckling_uc']:.3f}")
    """
    # Plate panel dimensions
    a = plate_length  # Length
    b = stiffener_spacing  # Width (between stiffeners)
    t = plate_thickness

    # Plate buckling coefficient
    # For simply supported rectangular plate under uniaxial compression:
    # σ_cr = k · π²E / (12(1-ν²)) · (t/b)²
    # where k depends on aspect ratio a/b

    aspect_ratio = a / b

    # Buckling coefficient k (for simply supported edges)
    if aspect_ratio >= 1:
        k = 4.0  # Long plate (a/b ≥ 1)
    else:
        k = (1 + aspect_ratio**2)**2 / aspect_ratio**2  # Short plate

    # Critical buckling stress for plate panel
    sigma_cr_plate = (
        k * np.pi**2 * E / (12 * (1 - nu**2)) * (t / b)**2
    )

    # Panel buckling unity check
    panel_buckling_uc = applied_stress / sigma_cr_plate

    # Stiffener + effective plate as column
    # Effective width of plate (participating in column buckling)
  

…(truncated)
