{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import pyvista\npyvista.OFF_SCREEN = True\npyvista.set_jupyter_backend('static')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Static cantilever \u2014 first example\n\nA 60-second introduction to femorph-solver's static analysis path: build a\nsteel cantilever beam as a structured pyvista grid, clamp the ``x=0``\nend, push the tip downward, and plot the deformed mesh.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from __future__ import annotations\n\nimport numpy as np\nimport pyvista as pv\n\nimport femorph_solver as fs"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Build a 10 \u00d7 2 \u00d7 2 hex cantilever\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "LX, LY, LZ = 1.0, 0.1, 0.1\n\ngrid = pv.StructuredGrid(\n    *np.meshgrid(\n        np.linspace(0.0, LX, 11),\n        np.linspace(0.0, LY, 3),\n        np.linspace(0.0, LZ, 3),\n        indexing=\"ij\",\n    )\n).cast_to_unstructured_grid()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Wrap as a :class:`femorph_solver.Model` and stamp steel\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "m = fs.Model.from_grid(grid)\nm.assign(fs.ELEMENTS.HEX8, material={\"EX\": 2.1e11, \"PRXY\": 0.30, \"DENS\": 7850.0})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Clamp the x=0 face, push the tip down with 10 kN distributed\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "x = np.asarray(grid.points)[:, 0]\nm.fix(where=x < 1e-9)\nm.apply_force(where=x > LX - 1e-9, fz=-10_000.0, total=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Solve + report\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res = m.solve_static()\nprint(f\"tip UZ = {res.displacement[2::3].min():.3e} m\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Plot the deformed shape\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "deformed = fs.io.static_result_to_grid(m, res)\nplotter = pv.Plotter(off_screen=True)\nplotter.add_mesh(deformed, style=\"wireframe\", color=\"gray\", opacity=0.35, label=\"undeformed\")\nplotter.add_mesh(\n    deformed.warp_by_vector(\"displacement\", factor=50.0),\n    scalars=\"displacement_magnitude\",\n    scalar_bar_args={\"title\": \"|u| [m]\"},\n    label=\"deformed (\u00d750)\",\n)\nplotter.add_legend()\nplotter.add_axes()\nplotter.show()"
      ]
    }
  ],
  "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.12.3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}