{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Compute Gradients of a Field {#gradients_example}\n\nEstimate the gradient of a scalar or vector field in a data set.\n\nThe ordering for the output gradient tuple will be {du/dx, du/dy, du/dz,\ndv/dx, dv/dy, dv/dz, dw/dx, dw/dy, dw/dz} for an input array {u, v, w}.\n\nShowing the\n`pyvista.DataSetFilters.compute_derivative`{.interpreted-text\nrole=\"func\"} filter.\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\n\n# A vtkStructuredGrid - but could be any mesh type\nmesh = examples.download_carotid()\nmesh"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Now compute the gradients of the `vectors` vector field in the point\ndata of that mesh. This is as simple as calling\n`pyvista.DataSetFilters.compute_derivative`{.interpreted-text\nrole=\"func\"}.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "mesh_g = mesh.compute_derivative(scalars=\"vectors\")\nmesh_g[\"gradient\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "::: note\n::: title\nNote\n:::\n\nYou can also use\n`pyvista.DataSetFilters.compute_derivative`{.interpreted-text\nrole=\"func\"} for computing other derivative based quantities, such as\ndivergence, vorticity, and Q-criterion. See function documentation for\noptions.\n:::\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "`mesh_g[\"gradient\"]` is an `N` by 9 NumPy array of the gradients, so we\ncould make a dictionary of NumPy arrays of the gradients like:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "def gradients_to_dict(arr):\n    \"\"\"A helper method to label the gradients into a dictionary.\"\"\"\n    keys = np.array(\n        [\"du/dx\", \"du/dy\", \"du/dz\", \"dv/dx\", \"dv/dy\", \"dv/dz\", \"dw/dx\", \"dw/dy\", \"dw/dz\"],\n    )\n    keys = keys.reshape((3, 3))[:, : arr.shape[1]].ravel()\n    return dict(zip(keys, mesh_g[\"gradient\"].T))\n\n\ngradients = gradients_to_dict(mesh_g[\"gradient\"])\ngradients"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "And we can add all of those components as individual arrays back to the\nmesh by:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "mesh_g.point_data.update(gradients)\nmesh_g"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "keys = np.array(list(gradients.keys())).reshape(3, 3)\n\np = pv.Plotter(shape=keys.shape)\nfor (i, j), name in np.ndenumerate(keys):\n    p.subplot(i, j)\n    p.add_mesh(mesh_g.contour(scalars=name), scalars=name, opacity=0.75)\n    p.add_mesh(mesh_g.outline(), color=\"k\")\np.link_views()\np.view_isometric()\np.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "And there you have it, the gradients for a vector field. We could also\ndo this for a scalar field like for the `scalars` field in the given\ndataset.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "mesh_g = mesh.compute_derivative(scalars=\"scalars\")\n\ngradients = gradients_to_dict(mesh_g[\"gradient\"])\ngradients"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "mesh_g.point_data.update(gradients)\n\nkeys = np.array(list(gradients.keys())).reshape(1, 3)\n\np = pv.Plotter(shape=keys.shape)\n\nfor (i, j), name in np.ndenumerate(keys):\n    name = keys[i, j]\n    p.subplot(i, j)\n    p.add_mesh(mesh_g.contour(scalars=name), scalars=name, opacity=0.75)\n    p.add_mesh(mesh_g.outline(), color=\"k\")\np.link_views()\np.view_isometric()\np.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.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}