{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n\n# Symmetric and Unsymmetric Beams in Complex Bending\n\nCalculate section properties of two different beams\ngiven in examples from 'Aircraft Structures,' by Peery.\nThese cases have known results, and the output from\n*sectionproperties* can be compared for accuracy. These\nexamples represent a more rigourous 'proof' against a\n'real' problem. Only results that have values in the\nreference material are tested here.\n\nBibTeX Entry for reference::\n\n    @Book{Peery,\n        title = {Aircraft Structures},\n        author = {David J. Peery},\n        organization = {Pensylvania State University},\n        publisher = {McGraw-Hill Book Company},\n        year = {1950},\n        edition = {First},\n        ISBN = {978-0486485805}\n    }\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from sectionproperties.pre.library import nastran_sections\nfrom sectionproperties.analysis.section import Section"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Example 1 in Sec. 6.2 (Symmetric Bending)\nThis is a symmetric I-section with no lateral supports,\nundergoing pure unidirectional cantilever bending.\nNote that units here are **inches**, to match the text.\n\nWe'll use a very coarse mesh here, to show a conservative\ncomparison for accuracy. Theoretically, with more\ndiscretization, we would capture the real results more accurately.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "geometry = nastran_sections.nastran_i(6, 3, 3, 1, 1, 1)\ngeometry = geometry.shift_section(x_offset=0, y_offset=-3)\ngeometry = geometry.create_mesh(mesh_sizes=[0.25])\nsection = Section(geometry)\nsection.plot_mesh()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Perform a geometric analysis on the section, and plot properties\nWe don't need warping analysis for these simple checks,\nbut sectionproperties needs them before evaluating stress.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "section.calculate_geometric_properties()\nsection.calculate_warping_properties()\nsection.plot_centroids()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Directly from the example, we know that the 2nd moment of inertia\nresisting the bending is 43.3 in\\ :sup:`4`.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "section.section_props.ixx_g"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "From statics, we know the max bending moment on the beam will\nbe 80,000 in-lbs. We can apply this moment to the section, and\nevaluate stress.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "moment = 8e5\nstress = section.calculate_stress(Mxx=moment)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Next we can extract the max stress from the section, and let's\ngo ahead and look at the calculated fringe plot. Refer to the\nstress example for details.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "numerical_result = max(stress.get_stress()[0][\"sig_zz\"])\nstress.plot_stress_zz()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "From the book, and simple statics, we know the max stress is\n55,427.3 psi.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "numerical_result"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This example is admittedly more simple, but it's still a nice\ncheck for the basics on validity of the package.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "print(f\"Theoretical Result = 55427 [psi]\")\nprint(f\"  Numerical Result = {numerical_result:.0f} [psi]\")\nacc = (55427 - numerical_result) / 55427\nprint(f\"          Accuracy = {acc:%}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Example 1 in Sec. 7.2. (Unsymmetric Bending)\nMoving on to something a bit more advanced...\nThis is an unsymmetric Z-section with no lateral supports.\nNote that units here are **inches**, to match the text.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "base_geom = nastran_sections.nastran_zed(4, 2, 8, 12)\nbase_geom = base_geom.shift_section(-5, -6)\nbase_geom = base_geom.create_mesh([0.25])\nsection = Section(base_geom)\nsection.calculate_geometric_properties()\nsection.calculate_warping_properties()\nsection.plot_centroids()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Checking each property against the reference text:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "props = section.section_props\nprint(\"    Property | Theoretical | Numerical\")\nprint(f\"    ixx_g    | {693.3:<12.1f}| {props.ixx_g:<.1f}\")\nprint(f\"    iyy_g    | {173.3:<12.1f}| {props.iyy_g:<.1f}\")\nprint(f\"    ixy_g    | {-240:<12.1f}| {props.ixy_g:<.1f}\")\nprint(f\"    i11_c    | {787:<12.1f}| {props.i11_c:<.1f}\")\nprint(f\"    i22_c    | {79.5:<12.1f}| {props.i22_c:<.1f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Section properties all look good, so we can move on to\nsome stress analysis. Before we do, we will need a quick\nfunction to pull stress at a certain point. This is a bit\nof a hack! Future versions of *sectionproperties* will have\na much more robust system for getting stress at an\narbitrary location. This particular function will work for\nthe locations we need, since we *know* a node will be there.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from typing import Tuple\n\n\ndef get_node(nodes, coord) -> Tuple[int, tuple]:\n    \"\"\"\n    This function will loop over the node list provided,\n    finding the index of the coordinates you want.\n    Returns the index in the nodes list, and the coords.\n    \"\"\"\n    for index, var in enumerate(nodes):\n        if all(var == coord):\n            return index, var\n        else:\n            continue\n\n    raise ValueError(f\"No node found with coordinates: {coord}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The load applied in the reference is -100,000 in-lbs about the\nx-axis, and 10,000 inb-lbs about the y-axis.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "stress = section.calculate_stress(Mxx=-1e5, Myy=1e4)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Check stress at location A (see `docs<label-testing>` page for details)\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "A = (-5, 4)\ntext_result = 1210\nn, _ = get_node(section.mesh_nodes, A)\nnumerical_result = stress.get_stress()[0][\"sig_zz\"][n]\nprint(text_result, numerical_result)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Check stress at location B (see `docs<label-testing>` page for details)\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "B = (-5, 6)\ntext_result = 580\nn, _ = get_node(section.mesh_nodes, B)\nnumerical_result = stress.get_stress()[0][\"sig_zz\"][n]\nprint(text_result, numerical_result)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Check stress at location C (see `docs<label-testing>` page for details)\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "C = (1, 6)\ntext_result = -2384\nn, _ = get_node(section.mesh_nodes, C)\nnumerical_result = stress.get_stress()[0][\"sig_zz\"][n]\nprint(text_result, numerical_result)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Looking at total axial stress over the section.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "stress.plot_stress_zz()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.15"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}