{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Visualize Modal Analysis of a Pump Bracket {#pump_bracket_example}\n\nThe following example demonstrates how to use PyVista to visualize the\nmodal analysis of a pump bracket based on point arrays representing mode\nshapes for different modes of vibration.\n\n**Background** Modal analysis is the study of the dynamic properties of\nmechanical structures in the frequency domain. It is a common technique\nin structural dynamics, particularly for automotive, aerospace, and\ncivil engineering applications.\n\nA mode shape is the deformation pattern that occurs at a specific\nnatural frequency, or mode, of a structure. When a structure is excited\nby an external force, it responds at all its natural frequencies with\neach mode shape being independent of the others. In this example, we\nwill visualize the mode shapes to get an understanding of how the pump\nbracket responds to different modes of vibration.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import numpy as np\n\nimport pyvista as pv\nfrom pyvista import examples"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Load the dataset\n\nStart by loading the dataset using `download_pump_bracket()\n<pyvista.examples.downloads.download_pump_bracket>`{.interpreted-text\nrole=\"func\"}.\n\nThis example demonstrates the visualization of the pump bracket\\'s mode\nshape, the representation of its magnitude, and an animation of its\ndisplacement. The dataset used in this example contains 10 mode shapes\n(disp_0 to disp_9).\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "dataset = examples.download_pump_bracket()\ndataset"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Plot the Dataset\n\nChoose a mode shape from the available arrays in the dataset. Each\n\\\"disp_N\\\" array represents an eigen solution or a single mode shape for\na given mode of vibration.\n\nPlot the 4th mode of the dataset. This is the first torsional mode for\nthe bracket.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "cpos = [\n    (0.744, -0.502, -0.830),\n    (0.0520, -0.160, 0.0743),\n    (-0.180, -0.958, 0.224),\n]\n\ndataset.plot(\n    scalars='disp_3',\n    cpos=cpos,\n    show_scalar_bar=False,\n    ambient=0.2,\n    anti_aliasing='fxaa',\n)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Visualize Displaced Mode Shape\n\nWe will now visualize the mode shapes of the pump bracket by displacing\nthe original dataset using\n`warp_by_vector <pyvista.DataSetFilters.warp_by_vector>`{.interpreted-text\nrole=\"func\"}.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Create a plotter\npl = pv.Plotter()\n\n# Add the undeformed pump bracket\npl.add_mesh(dataset, color=\"white\", opacity=0.5)\n\n# Add the deformed pump bracket with the mode shape\nwarp = dataset.warp_by_vector('disp_2', factor=0.1)\npl.add_mesh(warp, show_scalar_bar=False, ambient=0.2)\n\npl.camera_position = cpos\npl.enable_anti_aliasing('fxaa')\npl.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Animate the Mode Shape Displacement\n\nAnimate the mode shape\\'s displacement by updating the vertex positions\nat each time step. For a more realistic animation, we use a sinusoidal\nfunction to vary the displacement.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# feel free to change this to visualize different mode shapes\nmode_shape = 'disp_6'\n\n# copy the dataset as we will modify its coordinates\nds = dataset.copy()\n\npl = pv.Plotter(off_screen=True)\npl.add_mesh(ds, lighting=True, color='w')\npl.camera_position = cpos\npl.enable_anti_aliasing('fxaa')\n\nn_frames = 16\npl.open_gif(\"pump_bracket_mode_shape.gif\")\nfor phase in np.linspace(0, 2 * np.pi, n_frames, endpoint=False):\n    # use the original unmodified points, modify copy inplace\n    ds.points = dataset.points + ds[mode_shape] * np.cos(phase) * 0.05\n    pl.write_frame()\n\npl.close()"
      ]
    }
  ],
  "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.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}