{
  "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# Single-hex uniaxial tension \u2014 Hooke's law + Poisson check\n\nThe smallest possible verification: a unit cube of isotropic\nlinear elastic material under a uniform axial traction must\nreproduce 1-D Hooke's law $\\sigma_{xx} = E\\, \\varepsilon_{xx}$\nand Poisson contraction\n$\\varepsilon_{yy} = -\\nu\\, \\varepsilon_{xx}$ to machine\nprecision.\n\nReference: Hughes, T. J. R. *The Finite Element Method*, Dover,\n2000, \u00a72.7.\n\nThis gallery example drives the validation framework \u2014 the\n``PublishedValue`` carries the citation and the closed-form\nformula; the acceptance test at the bottom mirrors the\nregression guard in ``tests/validation/test_single_hex_uniaxial.py``.\n\n## Vendor cross-references\n\n======================================  =====================  ============================================\nSource                                   Reported \u03b5_xx          Problem ID / location\n======================================  =====================  ============================================\nClosed form (Hooke's law)                5.00 \u00d7 10\u207b\u2076            Cook CAFEA \u00a71.3 + Hughes FEM \u00a72.7\nNAFEMS Background to Benchmarks          5.00 \u00d7 10\u207b\u2076            BtB-2.1 (uniaxial tension test)\nAbaqus Verification Manual               5.00 \u00d7 10\u207b\u2076            AVM 1.3.1 (uniaxial stress, C3D8)\nMAPDL Verification Manual                5.00 \u00d7 10\u207b\u2076            VM-1 (statically indeterminate reaction force)\n======================================  =====================  ============================================\n\nEvery source agrees to the precision at which the value is stated.\nThis is the minimum bar an FE implementation has to clear \u2014 no\nsolver that ships results differing from Hooke's law on a single\nhex under uniaxial tension is correct.\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.problems import SingleHexUniaxial"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Instantiate the benchmark\nReports its published values in the order declared.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "problem = SingleHexUniaxial()\nprint(f\"benchmark: {problem.name}\")\nprint(problem.description)\nprint()\nfor ref in problem.published_values:\n    print(f\"  {ref.name:18s}  {ref.value:+.6e} {ref.unit:3s}  [source: {ref.source}]\")\n    print(f\"    formula: {ref.formula}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Run the validation\n``validate()`` builds the model, solves, and extracts each\npublished quantity.  The default single-hex mesh is enough \u2014\nthis problem is a direct consistency check, not a convergence\nstudy.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "results = problem.validate()\nprint(\"\\ncomputed vs published:\")\nprint(f\"  {'quantity':<18s} {'computed':>14s} {'published':>14s}  {'rel err':>10s}  pass\")\nfor r in results:\n    pass_str = \"\u2713\" if r.passed else \"\u2717\"\n    print(\n        f\"  {r.published.name:<18s} {r.computed:+14.6e} \"\n        f\"{r.published.value:+14.6e}  \"\n        f\"{r.rel_error * 100:+9.2e}%   {pass_str}\"\n    )"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Visualise the deformed shape\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "m = problem.build_model()\nres = m.solve_static()\nu = np.asarray(res.displacement).reshape(-1, 3)\n\n# Exaggerate the displacement 1000\u00d7 for visibility on the figure.\nwarped = m.grid.copy()\nwarped.points = m.grid.points + 1000.0 * u\n\nplotter = pv.Plotter(off_screen=True)\nplotter.add_mesh(m.grid, style=\"wireframe\", color=\"black\", line_width=1.5, label=\"undeformed\")\nplotter.add_mesh(warped, scalars=u[:, 0], show_edges=True, cmap=\"plasma\", label=\"deformed (\u00d71000)\")\nplotter.view_isometric()\nplotter.camera.zoom(1.2)\nplotter.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Acceptance\nMachine-precision pass is what Hooke's law demands.  Any\nregression here is either a constitutive-matrix / strain-kernel\nbug or a change in the solver residual; the framework surfaces\nboth equally well.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "for r in results:\n    assert r.passed, (\n        f\"{r.published.name} drifted above the published tolerance: \"\n        f\"rel_err={r.rel_error:.2e}, tol={r.published.tolerance:.2e}\"\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
}