Claude Code Plugins

Community-maintained marketplace

Feedback

structural-analysis

@vamseeachanta/digitalmodel
3
0

Perform structural analysis including stress calculations, buckling checks, and capacity verification per DNV, API, and ISO standards. Covers Von Mises stress, plate buckling, member capacity, and safety factor reporting.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name structural-analysis
description Perform structural analysis including stress calculations, buckling checks, and capacity verification per DNV, API, and ISO standards. Covers Von Mises stress, plate buckling, member capacity, and safety factor reporting.

Structural Analysis Skill

Perform structural analysis for offshore and marine structures including stress calculations, buckling checks, and capacity verification.

When to Use

  • Von Mises stress calculations
  • Plate buckling checks (DNV, API standards)
  • Member capacity verification
  • Combined loading assessment
  • Weld strength verification
  • Safety factor reporting
  • Standards compliance documentation

Supported Standards

Standard Application
DNV-RP-C201 Buckling strength of plated structures
DNV-RP-C202 Buckling strength of shells
DNV-RP-C203 Fatigue design
API RP 2A Fixed offshore platforms
ISO 19902 Fixed steel offshore structures
AISC 360 Steel construction
Eurocode 3 Steel structures

Implementation Pattern

Stress Calculations

from dataclasses import dataclass
from typing import Dict, List, Optional, Tuple
import numpy as np
import logging

logger = logging.getLogger(__name__)


@dataclass
class StressState:
    """Complete stress state at a point."""
    sigma_x: float = 0.0    # Normal stress in x direction (MPa)
    sigma_y: float = 0.0    # Normal stress in y direction (MPa)
    sigma_z: float = 0.0    # Normal stress in z direction (MPa)
    tau_xy: float = 0.0     # Shear stress xy (MPa)
    tau_xz: float = 0.0     # Shear stress xz (MPa)
    tau_yz: float = 0.0     # Shear stress yz (MPa)

    def von_mises(self) -> float:
        """Calculate Von Mises equivalent stress."""
        return np.sqrt(
            0.5 * (
                (self.sigma_x - self.sigma_y)**2 +
                (self.sigma_y - self.sigma_z)**2 +
                (self.sigma_z - self.sigma_x)**2 +
                6 * (self.tau_xy**2 + self.tau_xz**2 + self.tau_yz**2)
            )
        )

    def principal_stresses(self) -> Tuple[float, float, float]:
        """Calculate principal stresses."""
        # Build stress tensor
        tensor = np.array([
            [self.sigma_x, self.tau_xy, self.tau_xz],
            [self.tau_xy, self.sigma_y, self.tau_yz],
            [self.tau_xz, self.tau_yz, self.sigma_z]
        ])

        # Eigenvalues are principal stresses
        eigenvalues = np.linalg.eigvalsh(tensor)
        return tuple(sorted(eigenvalues, reverse=True))

    def max_shear(self) -> float:
        """Calculate maximum shear stress."""
        s1, s2, s3 = self.principal_stresses()
        return (s1 - s3) / 2


@dataclass
class MaterialProperties:
    """Material properties for structural analysis."""
    yield_strength: float     # MPa
    ultimate_strength: float  # MPa
    youngs_modulus: float     # MPa
    poissons_ratio: float
    density: float            # kg/m³
    name: str = "Steel"


# Common materials
STEEL_S355 = MaterialProperties(
    yield_strength=355,
    ultimate_strength=510,
    youngs_modulus=210000,
    poissons_ratio=0.3,
    density=7850,
    name="S355"
)

STEEL_S420 = MaterialProperties(
    yield_strength=420,
    ultimate_strength=520,
    youngs_modulus=210000,
    poissons_ratio=0.3,
    density=7850,
    name="S420"
)


class StressCalculator:
    """Calculate stresses in structural members."""

    def __init__(self, material: MaterialProperties):
        self.material = material

    def beam_stress(
        self,
        axial_force: float,
        moment_y: float,
        moment_z: float,
        area: float,
        I_y: float,
        I_z: float,
        y: float,
        z: float
    ) -> float:
        """
        Calculate bending stress in a beam.

        Args:
            axial_force: Axial force (N)
            moment_y: Moment about y-axis (N·m)
            moment_z: Moment about z-axis (N·m)
            area: Cross-sectional area (m²)
            I_y: Moment of inertia about y (m⁴)
            I_z: Moment of inertia about z (m⁴)
            y: Distance from neutral axis in y (m)
            z: Distance from neutral axis in z (m)

        Returns:
            Normal stress (MPa)
        """
        sigma_axial = axial_force / area / 1e6  # Convert to MPa
        sigma_bending_y = moment_y * z / I_y / 1e6
        sigma_bending_z = moment_z * y / I_z / 1e6

        return sigma_axial + sigma_bending_y + sigma_bending_z

    def shear_stress(
        self,
        shear_force: float,
        Q: float,
        I: float,
        t: float
    ) -> float:
        """
        Calculate shear stress using VQ/It formula.

        Args:
            shear_force: Shear force (N)
            Q: First moment of area (m³)
            I: Moment of inertia (m⁴)
            t: Thickness at section (m)

        Returns:
            Shear stress (MPa)
        """
        return shear_force * Q / (I * t) / 1e6

    def torsional_stress(
        self,
        torque: float,
        r: float,
        J: float
    ) -> float:
        """
        Calculate torsional shear stress.

        Args:
            torque: Applied torque (N·m)
            r: Radial distance from center (m)
            J: Polar moment of inertia (m⁴)

        Returns:
            Shear stress (MPa)
        """
        return torque * r / J / 1e6

    def hoop_stress(
        self,
        pressure: float,
        radius: float,
        thickness: float
    ) -> float:
        """
        Calculate hoop stress in thin-walled cylinder.

        Args:
            pressure: Internal pressure (MPa)
            radius: Inner radius (m)
            thickness: Wall thickness (m)

        Returns:
            Hoop stress (MPa)
        """
        return pressure * radius / thickness

    def longitudinal_stress(
        self,
        pressure: float,
        radius: float,
        thickness: float
    ) -> float:
        """
        Calculate longitudinal stress in thin-walled cylinder.

        Args:
            pressure: Internal pressure (MPa)
            radius: Inner radius (m)
            thickness: Wall thickness (m)

        Returns:
            Longitudinal stress (MPa)
        """
        return pressure * radius / (2 * thickness)

Buckling Analysis

@dataclass
class PlateGeometry:
    """Plate geometry for buckling analysis."""
    length: float       # a (mm)
    width: float        # b (mm)
    thickness: float    # t (mm)


@dataclass
class BucklingResult:
    """Results from buckling analysis."""
    critical_stress: float    # MPa
    applied_stress: float     # MPa
    utilization: float
    safety_factor: float
    mode: str
    passes: bool


class PlateBucklingAnalyzer:
    """
    Plate buckling analysis per DNV-RP-C201.
    """

    def __init__(self, material: MaterialProperties):
        self.material = material
        self.E = material.youngs_modulus
        self.nu = material.poissons_ratio
        self.fy = material.yield_strength

    def elastic_buckling_stress(
        self,
        plate: PlateGeometry,
        boundary_conditions: str = "simply_supported"
    ) -> float:
        """
        Calculate elastic buckling stress.

        Args:
            plate: Plate geometry
            boundary_conditions: Boundary condition type

        Returns:
            Elastic buckling stress (MPa)
        """
        a = plate.length
        b = plate.width
        t = plate.thickness

        # Aspect ratio
        alpha = a / b

        # Buckling coefficient (simply supported, uniform compression)
        if alpha < 1:
            k = (alpha + 1/alpha)**2
        else:
            k = 4.0

        # Elastic buckling stress
        sigma_e = k * np.pi**2 * self.E / (12 * (1 - self.nu**2)) * (t / b)**2

        return sigma_e

    def reduced_slenderness(
        self,
        plate: PlateGeometry
    ) -> float:
        """
        Calculate reduced slenderness parameter.

        Args:
            plate: Plate geometry

        Returns:
            Reduced slenderness (lambda_p)
        """
        sigma_e = self.elastic_buckling_stress(plate)
        return np.sqrt(self.fy / sigma_e)

    def johnson_ostenfeld(
        self,
        sigma_e: float
    ) -> float:
        """
        Apply Johnson-Ostenfeld correction for inelastic buckling.

        Args:
            sigma_e: Elastic buckling stress

        Returns:
            Critical buckling stress
        """
        if sigma_e <= 0.5 * self.fy:
            return sigma_e
        else:
            return self.fy * (1 - self.fy / (4 * sigma_e))

    def check_plate_buckling(
        self,
        plate: PlateGeometry,
        sigma_x: float,
        sigma_y: float = 0.0,
        tau: float = 0.0,
        gamma_m: float = 1.15
    ) -> BucklingResult:
        """
        Check plate buckling under combined loading.

        Args:
            plate: Plate geometry
            sigma_x: Compressive stress in x (MPa, positive = compression)
            sigma_y: Compressive stress in y (MPa)
            tau: Shear stress (MPa)
            gamma_m: Material factor

        Returns:
            BucklingResult with utilization
        """
        # Calculate individual buckling stresses
        b = plate.width
        t = plate.thickness

        # Compressive buckling
        sigma_e_x = self.elastic_buckling_stress(plate)
        sigma_cr_x = self.johnson_ostenfeld(sigma_e_x)

        # Shear buckling
        k_tau = 5.34 + 4 * (b / plate.length)**2
        tau_e = k_tau * np.pi**2 * self.E / (12 * (1 - self.nu**2)) * (t / b)**2
        tau_cr = self.johnson_ostenfeld(tau_e)

        # Combined check (interaction formula)
        util_x = sigma_x / (sigma_cr_x / gamma_m) if sigma_cr_x > 0 else 0
        util_tau = (tau / (tau_cr / gamma_m))**2 if tau_cr > 0 else 0

        total_util = util_x + util_tau

        return BucklingResult(
            critical_stress=sigma_cr_x,
            applied_stress=sigma_x,
            utilization=total_util,
            safety_factor=1 / total_util if total_util > 0 else float('inf'),
            mode="plate_buckling",
            passes=total_util <= 1.0
        )


class ColumnBucklingAnalyzer:
    """
    Column buckling analysis per Eurocode 3.
    """

    def __init__(self, material: MaterialProperties):
        self.material = material
        self.E = material.youngs_modulus
        self.fy = material.yield_strength

    def euler_buckling_load(
        self,
        I: float,
        L_eff: float
    ) -> float:
        """
        Calculate Euler critical buckling load.

        Args:
            I: Moment of inertia (mm⁴)
            L_eff: Effective length (mm)

        Returns:
            Critical load (N)
        """
        return np.pi**2 * self.E * I / L_eff**2

    def slenderness_ratio(
        self,
        L_eff: float,
        r: float
    ) -> float:
        """
        Calculate slenderness ratio.

        Args:
            L_eff: Effective length (mm)
            r: Radius of gyration (mm)

        Returns:
            Slenderness ratio
        """
        return L_eff / r

    def reduction_factor(
        self,
        lambda_bar: float,
        buckling_curve: str = "b"
    ) -> float:
        """
        Calculate buckling reduction factor per EC3.

        Args:
            lambda_bar: Non-dimensional slenderness
            buckling_curve: EC3 buckling curve (a0, a, b, c, d)

        Returns:
            Reduction factor chi
        """
        # Imperfection factors
        alpha_dict = {
            "a0": 0.13,
            "a": 0.21,
            "b": 0.34,
            "c": 0.49,
            "d": 0.76
        }
        alpha = alpha_dict.get(buckling_curve, 0.34)

        # Calculate reduction factor
        phi = 0.5 * (1 + alpha * (lambda_bar - 0.2) + lambda_bar**2)
        chi = 1 / (phi + np.sqrt(phi**2 - lambda_bar**2))

        return min(chi, 1.0)

    def check_column_buckling(
        self,
        axial_force: float,
        area: float,
        I_min: float,
        L_eff: float,
        buckling_curve: str = "b",
        gamma_m: float = 1.0
    ) -> BucklingResult:
        """
        Check column buckling capacity.

        Args:
            axial_force: Applied axial force (N)
            area: Cross-sectional area (mm²)
            I_min: Minimum moment of inertia (mm⁴)
            L_eff: Effective length (mm)
            buckling_curve: EC3 curve
            gamma_m: Material factor

        Returns:
            BucklingResult
        """
        # Calculate slenderness
        r = np.sqrt(I_min / area)
        lambda_1 = np.pi * np.sqrt(self.E / self.fy)
        lambda_bar = (L_eff / r) / lambda_1

        # Get reduction factor
        chi = self.reduction_factor(lambda_bar, buckling_curve)

        # Design capacity
        N_cr = chi * area * self.fy / gamma_m

        # Utilization
        util = axial_force / N_cr if N_cr > 0 else float('inf')

        return BucklingResult(
            critical_stress=chi * self.fy / gamma_m,
            applied_stress=axial_force / area,
            utilization=util,
            safety_factor=1 / util if util > 0 else float('inf'),
            mode="column_buckling",
            passes=util <= 1.0
        )

Capacity Verification

@dataclass
class CapacityResult:
    """Results from capacity check."""
    capacity: float
    demand: float
    utilization: float
    governing_mode: str
    passes: bool
    details: Dict


class MemberCapacityChecker:
    """
    Check member capacity for combined loading.
    """

    def __init__(self, material: MaterialProperties):
        self.material = material
        self.stress_calc = StressCalculator(material)
        self.plate_buckling = PlateBucklingAnalyzer(material)
        self.column_buckling = ColumnBucklingAnalyzer(material)

    def check_tension_member(
        self,
        axial_force: float,
        area_gross: float,
        area_net: float,
        gamma_m0: float = 1.0,
        gamma_m2: float = 1.25
    ) -> CapacityResult:
        """
        Check tension capacity per EC3.

        Args:
            axial_force: Applied tension (N)
            area_gross: Gross area (mm²)
            area_net: Net area at connections (mm²)
            gamma_m0: Material factor (yield)
            gamma_m2: Material factor (ultimate)

        Returns:
            CapacityResult
        """
        # Plastic capacity
        N_pl = area_gross * self.material.yield_strength / gamma_m0

        # Ultimate capacity at net section
        N_u = 0.9 * area_net * self.material.ultimate_strength / gamma_m2

        # Governing capacity
        N_Rd = min(N_pl, N_u)
        governing = "plastic" if N_pl <= N_u else "net_section"

        util = axial_force / N_Rd if N_Rd > 0 else float('inf')

        return CapacityResult(
            capacity=N_Rd,
            demand=axial_force,
            utilization=util,
            governing_mode=governing,
            passes=util <= 1.0,
            details={'N_pl': N_pl, 'N_u': N_u}
        )

    def check_combined_loading(
        self,
        N: float,
        M_y: float,
        M_z: float,
        area: float,
        W_pl_y: float,
        W_pl_z: float,
        N_cr_y: float,
        N_cr_z: float,
        gamma_m1: float = 1.0
    ) -> CapacityResult:
        """
        Check member under combined axial and bending.

        Args:
            N: Axial force (N, positive = compression)
            M_y: Moment about y-axis (N·mm)
            M_z: Moment about z-axis (N·mm)
            area: Cross-sectional area (mm²)
            W_pl_y: Plastic section modulus y (mm³)
            W_pl_z: Plastic section modulus z (mm³)
            N_cr_y: Critical buckling load y (N)
            N_cr_z: Critical buckling load z (N)
            gamma_m1: Material factor

        Returns:
            CapacityResult
        """
        fy = self.material.yield_strength

        # Capacities
        N_Rk = area * fy
        M_y_Rk = W_pl_y * fy
        M_z_Rk = W_pl_z * fy

        # Reduction factors
        chi_y = N_cr_y / N_Rk if N_Rk > 0 else 1.0
        chi_z = N_cr_z / N_Rk if N_Rk > 0 else 1.0
        chi = min(chi_y, chi_z, 1.0)

        # Interaction check (simplified)
        util_N = N / (chi * N_Rk / gamma_m1) if N > 0 else 0
        util_My = M_y / (M_y_Rk / gamma_m1)
        util_Mz = M_z / (M_z_Rk / gamma_m1)

        # Combined utilization (simplified linear)
        util_combined = util_N + util_My + util_Mz

        return CapacityResult(
            capacity=chi * N_Rk / gamma_m1,
            demand=N,
            utilization=util_combined,
            governing_mode="combined",
            passes=util_combined <= 1.0,
            details={
                'util_N': util_N,
                'util_My': util_My,
                'util_Mz': util_Mz
            }
        )

YAML Configuration

# config/structural_analysis.yaml

material:
  name: S355
  yield_strength: 355  # MPa
  ultimate_strength: 510
  youngs_modulus: 210000
  poissons_ratio: 0.3

plates:
  - id: bottom_plate
    length: 2000
    width: 1000
    thickness: 20
    loading:
      sigma_x: 150
      sigma_y: 0
      tau: 30

  - id: side_plate
    length: 3000
    width: 1500
    thickness: 16
    loading:
      sigma_x: 200
      sigma_y: 50
      tau: 40

columns:
  - id: leg_1
    area: 15000  # mm²
    I_min: 5.0e7  # mm⁴
    L_eff: 8000  # mm
    buckling_curve: b
    axial_force: 2500000  # N

safety_factors:
  gamma_m0: 1.0
  gamma_m1: 1.0
  gamma_m2: 1.25

output:
  report_path: reports/structural_analysis.html
  include_plots: true

Usage Examples

Stress Analysis

from structural_analysis import StressState, StressCalculator, STEEL_S355

# Create stress state
stress = StressState(
    sigma_x=150.0,
    sigma_y=50.0,
    tau_xy=30.0
)

# Calculate Von Mises
vm = stress.von_mises()
print(f"Von Mises stress: {vm:.1f} MPa")

# Check against yield
sf = STEEL_S355.yield_strength / vm
print(f"Safety factor: {sf:.2f}")

Buckling Check

from structural_analysis import (
    PlateBucklingAnalyzer, PlateGeometry, STEEL_S355
)

analyzer = PlateBucklingAnalyzer(STEEL_S355)

plate = PlateGeometry(
    length=2000,
    width=1000,
    thickness=20
)

result = analyzer.check_plate_buckling(
    plate=plate,
    sigma_x=150,
    tau=30,
    gamma_m=1.15
)

print(f"Utilization: {result.utilization:.2%}")
print(f"Status: {'PASS' if result.passes else 'FAIL'}")

Combined Capacity Check

from structural_analysis import MemberCapacityChecker, STEEL_S355

checker = MemberCapacityChecker(STEEL_S355)

result = checker.check_combined_loading(
    N=2500000,  # N
    M_y=500e6,  # N·mm
    M_z=200e6,  # N·mm
    area=15000,
    W_pl_y=2.5e6,
    W_pl_z=1.5e6,
    N_cr_y=8e6,
    N_cr_z=6e6
)

print(f"Combined utilization: {result.utilization:.2%}")

Best Practices

Analysis Approach

  • Start with simple hand calculations
  • Verify FEA results with analytical methods
  • Check all load combinations
  • Include manufacturing tolerances

Safety Factors

  • Use code-specified factors
  • Document any deviations
  • Consider consequence of failure
  • Account for inspection limitations

Documentation

  • Clearly state assumptions
  • Reference applicable standards
  • Show detailed calculations
  • Include sensitivity checks

Related Skills