{
  "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# Cantilever tip deflection \u2014 Euler-Bernoulli closed form\n\nSlender clamped cantilever under a transverse tip load has\ntip deflection\n\n\\begin{align}\\delta = \\frac{P L^{3}}{3 E I}, \\qquad I = \\frac{w h^{3}}{12}.\\end{align}\n\nReference: Timoshenko, S. P. *Strength of Materials, Part I*,\n3rd ed., Van Nostrand, 1955, \u00a75.4.\n\nThis gallery example drives a multi-refinement\n:class:`~femorph_solver.validation.ConvergenceStudy` and\nrenders the deformed shape at the finest mesh.\n\n## Vendor cross-references\n\n======================================  =====================  ============================================\nSource                                   Reported \u03b4 [m]         Problem ID / location\n======================================  =====================  ============================================\nClosed form (Euler-Bernoulli)            3.81 \u00d7 10\u207b\u2075            Timoshenko SoM Part I \u00a75.4\nNAFEMS Background to Benchmarks \u00a73.1     3.81 \u00d7 10\u207b\u2075            NAFEMS BtB-3.1 (cantilever)\nMAPDL Verification Manual                3.81 \u00d7 10\u207b\u2075            VM-2 (beam stresses and deflections)\nAbaqus Verification Manual               3.81 \u00d7 10\u207b\u2075            AVM 1.4.3 (cantilever with end shear)\nCalculiX ccx/test/beamp.inp              3.80 \u00d7 10\u207b\u2075            CalculiX 2.21 statics test\n======================================  =====================  ============================================\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\nfrom femorph_solver.validation import ConvergenceStudy\nfrom femorph_solver.validation.problems import CantileverEulerBernoulli"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Problem + convergence ladder\n\nThree in-plane refinements (slenderness L/h = 20); three\ntransverse layers keeps the shear-strain field resolved at\nthe HEX8 EAS formulation used under the hood.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "problem = CantileverEulerBernoulli()\nstudy = ConvergenceStudy(\n    problem=problem,\n    refinements=[\n        {\"nx\": 20, \"ny\": 3, \"nz\": 3},\n        {\"nx\": 40, \"ny\": 3, \"nz\": 3},\n        {\"nx\": 80, \"ny\": 3, \"nz\": 3},\n    ],\n)\nrecords = study.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Print the comparison table\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "rec = records[0]\npub = rec.results[0].published\nprint(f\"{problem.name}: {problem.description}\")\nprint(f\"\\n  source : {pub.source}\")\nprint(f\"  formula: {pub.formula}\")\nprint(f\"  published: {pub.value:.6e} {pub.unit}\\n\")\nprint(f\"  {'mesh':<20s} {'n_dof':>8s} {'computed':>14s} {'rel err':>10s}  pass\")\nfor r in rec.results:\n    mesh_str = \"  \".join(f\"{k}={v}\" for k, v in r.mesh_params.items())\n    pass_str = \"\u2713\" if r.passed else \"\u2717\"\n    print(\n        f\"  {mesh_str:<20s} {r.n_dof:>8d} {r.computed:+14.6e} \"\n        f\"{r.rel_error * 100:+9.2f}%   {pass_str}\"\n    )\nif rec.convergence_rate is not None:\n    print(f\"\\n  fitted rate: |err| \u221d n_dof^(-{rec.convergence_rate:.2f})\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Render the deformed shape at the finest mesh\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "m = problem.build_model(nx=80, ny=3, nz=3)\nres = m.solve_static()\nu = np.asarray(res.displacement).reshape(-1, 3)\n\nwarped = m.grid.copy()\nwarped.points = m.grid.points + 1.0 * u\nwarped[\"|u|\"] = np.linalg.norm(u, axis=1)\n\nplotter = pv.Plotter(off_screen=True)\nplotter.add_mesh(m.grid, style=\"wireframe\", color=\"#888888\", opacity=0.3)\nplotter.add_mesh(warped, scalars=\"|u|\", cmap=\"viridis\", show_edges=False)\nplotter.view_isometric()\nplotter.camera.zoom(1.1)\nplotter.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Acceptance\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "finest = rec.results[-1]\nassert finest.passed, (\n    f\"finest-mesh tip_deflection failed: {finest.rel_error:.2%} \"\n    f\"above tolerance {finest.published.tolerance:.0%}\"\n)"
      ]
    }
  ],
  "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
}