{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Coordinate systems" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebooks provides examples of curvilinear coordinates. Particularly,\n", "it presents the coordinate surfaces for three common coordinate systems." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Use of PyVista in this notebook" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We use `PyVista` to represent the coordinate surfaces and `ìtkwidgets`\n", "to render them interactively in the notebook.\n", "\n", "If installing things manually, the following would be required\n", "\n", "\n", " conda install -c conda-forge pyvista\n", " conda install -c conda-forge itkwidgets\n", "\n", "\n", "**More information:** https://docs.pyvista.org/examples/index.html" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pyvista as pv\n", "from itkwidgets import view" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "red = (0.9, 0.1, 0.1)\n", "blue = (0.2, 0.5, 0.7)\n", "green = (0.3, 0.7, 0.3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cylindrical coordinates\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The [ISO standard 80000-2](https://en.wikipedia.org/wiki/ISO_80000-2) recommends the use of $(ρ, φ, z)$, where $ρ$ is the radial coordinate, $\\varphi$ the azimuth, and $z$ the height.\n", "\n", "For the conversion between cylindrical and Cartesian coordinates, it is convenient to assume that the reference plane of the former is the Cartesian $xy$-plane (with equation $z=0$, and the cylindrical axis is the Cartesian $z$-axis. Then the $z$-coordinate is the same in both systems, and the correspondence between cylindrical $(\\rho, \\varphi)$ and Cartesian $(x, y)$ are the same as for polar coordinates, namely\n", "\n", "\\begin{align}\n", "x &= \\rho \\cos \\varphi \\\\\n", "y &= \\rho \\sin \\varphi\n", "\\end{align}\n", "\n", "in one direction, and\n", "\n", "\\begin{align}\n", " \\rho &= \\sqrt{x^2+y^2} \\\\\n", " \\varphi &= \\begin{cases}\n", " 0 & \\mbox{if } x = 0 \\mbox{ and } y = 0\\\\\n", " \\arcsin\\left(\\frac{y}{\\rho}\\right) & \\mbox{if } x \\geq 0 \\\\\t\n", " \\arctan\\left(\\frac{y}{x}\\right) & \\mbox{if } x > 0 \\\\\t\n", " -\\arcsin\\left(\\frac{y}{\\rho}\\right) + \\pi & \\mbox{if } x < 0\n", " \\end{cases}\n", "\\end{align}\n", "\n", "in the other. It is also common to use [$\\varphi = \\mathrm{atan2}(y, x)$](https://en.wikipedia.org/wiki/Atan2)." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Cylinder\n", "phi, z = np.mgrid[0:2*np.pi:31j, -2:2*np.pi:31j]\n", "x = 2*np.cos(phi)\n", "y = 2*np.sin(phi)\n", "cylinder = pv.StructuredGrid(x, y, z)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Vertical plane\n", "rho, z = np.mgrid[0:3:31j, -2:2*np.pi:31j]\n", "x = rho*np.cos(np.pi/4)\n", "y = rho*np.sin(np.pi/4)\n", "vert_plane = pv.StructuredGrid(x, y, z)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Horizontal plane\n", "rho, phi = np.mgrid[0:3:31j, 0:2*np.pi:31j]\n", "x = rho*np.cos(phi)\n", "y = rho*np.sin(phi)\n", "z = np.ones_like(x)\n", "hor_plane = pv.StructuredGrid(x, y, z)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "29a27643a8434035b33c11db8da76bec", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'name': '_points', 'numberO…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "view(geometries=[cylinder, vert_plane, hor_plane],\n", " geometry_colors=[blue, red, green])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Spherical coordinates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The use of $(r, θ, φ)$ to denote radial distance, inclination (or elevation), and azimuth, respectively, is common practice in physics, and is specified by [ISO standard 80000-2](https://en.wikipedia.org/wiki/ISO_80000-2).\n", "\n", "\n", "The spherical coordinates of a point can be obtained from its [Cartesian coordinate system](https://en.wikipedia.org/wiki/ISO_80000-2) $(x, y, z)$\n", "\n", "\\begin{align}\n", "r&=\\sqrt{x^2 + y^2 + z^2} \\\\\n", "\\theta &= \\arccos\\frac{z}{\\sqrt{x^2 + y^2 + z^2}} = \\arccos\\frac{z}{r} \\\\\n", "\\varphi &= \\arctan \\frac{y}{x}\n", "\\end{align}\n", "\n", "The inverse tangent denoted in $\\varphi = \\arctan\\left(\\frac{y}{x}\\right)$ must be suitably defined , taking into account the correct quadrant of $(x, y)$ (using the function ``atan2``).\n", "\n", "Conversely, the Cartesian coordinates may be retrieved from the spherical coordinates (_radius_ $r$, _inclination_ $\\theta$, _azimuth_ $\\varphi$), where $r \\in [0, \\infty)$, $\\theta \\in [0, \\pi]$ and $\\varphi \\in [0, 2\\pi)$, by:\n", "\n", "\\begin{align}\n", "x&=r \\, \\sin\\theta \\, \\cos\\varphi \\\\\n", "y&=r \\, \\sin\\theta \\, \\sin\\varphi \\\\\n", "z&=r \\, \\cos\\theta\n", "\\end{align}" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "theta, phi = np.mgrid[0:np.pi:21j, 0:np.pi:21j]" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# Sphere\n", "x = np.sin(phi) * np.cos(theta)\n", "y = np.sin(phi) * np.sin(theta)\n", "z = np.cos(phi)\n", "sphere = pv.StructuredGrid(x, y, z)\n", "sphere2 = pv.StructuredGrid(-x, -y, z)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# Cone\n", "x = theta/3 * np.cos(phi)\n", "y = theta/3 * np.sin(phi)\n", "z = theta/3\n", "cone = pv.StructuredGrid(x, y, z)\n", "cone2 = pv.StructuredGrid(-x, -y, z)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# Plane\n", "x = theta/np.pi\n", "y = theta/np.pi\n", "z = phi - np.pi/2\n", "plane = pv.StructuredGrid(x, y, z)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "99f523032243438d93c4431e154dc150", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'name': '_points', 'numberO…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "view(geometries=[sphere, sphere2, cone, cone2, plane],\n", " geometry_colors=[blue, blue, red, red, green],\n", " geometry_opacities=[1.0, 0.5, 1.0, 0.5, 1.0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ellipsoidal coordinates" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "v, theta = np.mgrid[0:np.pi/2:21j, 0:np.pi:21j]\n", "a = 3\n", "b = 2\n", "c = 1" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "# Ellipsoid\n", "lam = 3\n", "x = np.sqrt(a**2 + lam) * np.cos(v) * np.cos(theta)\n", "y = np.sqrt(b**2 + lam)* np.cos(v) * np.sin(theta)\n", "z = np.sqrt(c**2 + lam) * np.sin(v)\n", "ellipsoid = pv.StructuredGrid(x, y, z)\n", "ellipsoid2 = pv.StructuredGrid(x, y, -z)\n", "ellipsoid3 = pv.StructuredGrid(x, -y, z)\n", "ellipsoid4 = pv.StructuredGrid(x, -y, -z)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "# Hyperboloid of one sheet\n", "mu = 2\n", "x = np.sqrt(a**2 + mu) * np.cosh(v) * np.cos(theta)\n", "y = np.sqrt(b**2 + mu) * np.cosh(v) * np.sin(theta)\n", "z = np.sqrt(c**2 + mu) * np.sinh(v)\n", "z = np.sqrt(c**2 + mu) * np.sinh(v)\n", "hyper = pv.StructuredGrid(x, y, z)\n", "hyper2 = pv.StructuredGrid(x, y, -z)\n", "hyper3 = pv.StructuredGrid(x, -y, z)\n", "hyper4 = pv.StructuredGrid(x, -y, -z)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "# Hyperboloid of two sheets\n", "nu = 1\n", "x = np.sqrt(a**2 + nu) * np.cosh(v)\n", "y = np.sqrt(c**2 + nu) * np.sinh(v) * np.sin(theta)\n", "z = np.sqrt(b**2 + nu) * np.sinh(v) * np.cos(theta)\n", "hyper_up = pv.StructuredGrid(x, y, z)\n", "hyper_down = pv.StructuredGrid(-x, y, z)\n", "hyper_up2 = pv.StructuredGrid(x, -y, z)\n", "hyper_down2 = pv.StructuredGrid(-x, -y, z)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "c7d007e315d6443eae22c9b9655b22e1", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'name': '_points', 'numberO…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "view(geometries=[ellipsoid, ellipsoid2, ellipsoid3, ellipsoid4,\n", " hyper, hyper2, hyper3, hyper4,\n", " hyper_up, hyper_down, hyper_up2, hyper_down2],\n", " geometry_colors=[blue]*4 + [red]*4 + [green]*4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Wikipedia contributors. [\"Cylindrical coordinate system.\"](https://en.wikipedia.org/wiki/Cylindrical_coordinate_system) Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 12 Dec. 2016. Web. 9 Feb. 2017.\n", "\n", "2. Wikipedia contributors. [\"Spherical coordinate system.\"](https://en.wikipedia.org/wiki/Spherical_coordinate_system) Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 29 Jan. 2017. Web. 9 Feb. 2017.\n", "\n", "3. Sullivan et al., (2019). [PyVista: 3D plotting and mesh analysis through a streamlined interface for the Visualization Toolkit (VTK)](https://joss.theoj.org/papers/10.21105/joss.01450). Journal of Open Source Software, 4(37), 1450, https://doi.org/10.21105/joss.01450" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.core.display import HTML\n", "def css_styling():\n", " styles = open('./styles/custom_barba.css', 'r').read()\n", " return HTML(styles)\n", "css_styling()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.6.7" }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }