{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Field operations\n", "\n", "There are several convenience methods that can be used to analyse the field. Let us first define the mesh we are going to work with." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "import discretisedfield as df\n", "\n", "p1 = (-50, -50, -50)\n", "p2 = (50, 50, 50)\n", "n = (2, 2, 2)\n", "mesh = df.Mesh(p1=p1, p2=p2, n=n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We are going to initialise the vector field (`dim=3`), with\n", "\n", "$$\\mathbf{f}(x, y, z) = (xy, 2xy, xyz)$$\n", "\n", "For that, we are going to use the following Python function." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def value_function(pos):\n", " x, y, z = pos\n", " return x * y, 2 * x * y, x * y * z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, our field is" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "field = df.Field(mesh, dim=3, value=value_function)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sampling the field\n", "\n", "As we have shown previously, a field can be sampled by calling it. The argument must be a 3-length iterable and it contains the coordinates of the point." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(625.0, 1250.0, -15625.0)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "point = (0, 0, 0)\n", "field(point)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However if the point is outside the mesh, an exception is raised." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Exception raised.\n" ] } ], "source": [ "point = (100, 100, 100)\n", "try:\n", " field(point)\n", "except ValueError:\n", " print(\"Exception raised.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extracting the component of a vector field\n", "\n", "A three-dimensional vector field can be understood as three separate scalar fields, where each scalar field is a component of a vector field value. A scalar field of a component can be extracted by accessing `x`, `y`, or `z` attribute of the field." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "625.0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x_component = field.x\n", "x_component((0, 0, 0))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(-50, -50, -50), p2=(50, 50, 50)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Default names `x`, `y`, and (for dim 3) `z` are only available for fields with dimensionality 2 or 3." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['x', 'y', 'z']" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.components" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to change the component names:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "625.0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.components = [\"mx\", \"my\", \"mz\"]\n", "field.mx((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This overrides the component labels and the old `x`, `y` and `z` cannot be used anymore:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Object has no attribute x.\n" ] } ], "source": [ "try:\n", " field.x\n", "except AttributeError as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We change the component labels back to `x`, `y`, and `z` for the rest of this notebook." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "field.components = [\"x\", \"y\", \"z\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Custom component names can optionally also be specified during field creation. If not specified, the default values are used for fields with dimensions 2 or 3. Higher-dimensional fields have no defaults and custom labes have to be specified in order to access individual field components:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(-50, -50, -50), p2=(50, 50, 50)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=4, components: (c1, c2, c3, c4))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field_4d = df.Field(\n", " mesh, dim=4, value=[1, 1, 1, 1], components=[\"c1\", \"c2\", \"c3\", \"c4\"]\n", ")\n", "field_4d" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field_4d.c1((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extracting smaller region\n", "\n", "Let us say we are not interested in the entire field but only in its smaller portion - only some discretisation cells. In that case, we have two options. Before we discuss them, let us first define what we mean by \"aligned\" meshes:\n", "\n", "- Mesh A is aligned to mesh B if and only if all cell coordinates of mesh A are also the coordinates of (some) cells in mesh B.\n", "\n", "There is `|` operator which checks that. Let us have a look at a few meshes:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "mesh1 = df.Mesh(region=df.Region(p1=(0, 0, 0), p2=(10, 10, 10)), cell=(1, 1, 1))\n", "mesh2 = df.Mesh(region=df.Region(p1=(3, 3, 3), p2=(6, 6, 6)), cell=(1, 1, 1))\n", "mesh3 = df.Mesh(region=df.Region(p1=(0, 0, 0), p2=(10, 10, 10)), cell=(2, 2, 2))\n", "mesh4 = df.Mesh(\n", " region=df.Region(p1=(3.5, 3.5, 3.5), p2=(6.5, 6.5, 6.5)), cell=(1, 1, 1)\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us now have a look if those meshes are aligned:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mesh1 | mesh2" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mesh1 | mesh3 # discretisation cell is different" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mesh1 | mesh4 # although discretisation cell is the same, mesh4 is shifted in space by 0.5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Extracting subfield on aligned mesh\n", "\n", "If we want to get a subfield whose mesh is aligned to the field we want to take part of, we use `[]` operator. The resulting field is going to have a minimum-sized mesh which contains the region we pass as an argument." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(0.0, 0.0, 0.0), p2=(50.0, 50.0, 50.0)), n=(1, 1, 1), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subregion = df.Region(p1=(1.5, 2.2, 3.9), p2=(6.1, 5.9, 9.9))\n", "field[subregion]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see that the resulting field's mesh has the minimum dimesions aligned mesh should have in order to contain the `subregion`. The resulting field has the same discretisation cell as the original one.\n", "\n", "### Extracting field on any mesh\n", "\n", "If we want to extact part of the field on any mesh which is contained inside the field, we do that by \"resampling\". We create a new field on a submesh and pass the field we want take subfield from as `value`." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(1.5, 2.5, 3.5), p2=(5.5, 5.5, 6.5)), n=(8, 6, 6), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subregion = df.Region(p1=(1.5, 2.5, 3.5), p2=(5.5, 5.5, 6.5))\n", "submesh = df.Mesh(region=subregion, cell=(0.5, 0.5, 0.5))\n", "df.Field(submesh, dim=3, value=field)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One could ask why don't we always use resampling because it is a generalised case. The reason is because computing a subfield using `[]` operator is much faster." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computing the average\n", "\n", "The average of the field can be obtained by calling `discretisedfield.Field.average` property." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(0.0, 0.0, 0.0)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Average always return a tuple, independent of the dimension of the field's value." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.x.average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Iterating through the field\n", "\n", "The field object itself is an iterable. That means that it can be iterated through. As a result it returns a tuple, where the first element is the coordinate of the mesh point, whereas the second one is its value." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(-25.0, -25.0, -25.0) (625.0, 1250.0, -15625.0)\n", "(25.0, -25.0, -25.0) (-625.0, -1250.0, 15625.0)\n", "(-25.0, 25.0, -25.0) (-625.0, -1250.0, 15625.0)\n", "(25.0, 25.0, -25.0) (625.0, 1250.0, -15625.0)\n", "(-25.0, -25.0, 25.0) (625.0, 1250.0, 15625.0)\n", "(25.0, -25.0, 25.0) (-625.0, -1250.0, -15625.0)\n", "(-25.0, 25.0, 25.0) (-625.0, -1250.0, -15625.0)\n", "(25.0, 25.0, 25.0) (625.0, 1250.0, 15625.0)\n" ] } ], "source": [ "for coordinate, value in field:\n", " print(coordinate, value)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sampling the field along the line\n", "\n", "To sample the points of the field which are on a certain line, `discretisedfield.Field.line` method is used. It takes two points `p1` and `p2` that define the line and an integer `n` which defines how many mesh coordinates on that line are required. The default value of `n` is 100." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "line = field.line(p1=(-10, 0, 0), p2=(10, 0, 0), n=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Intersecting the field with a plane\n", "\n", "If we intersect the field with a plane, `discretisedfield.Field.plane` will return a new field object which contains only discretisation cells that belong to that plane. The planes allowed are the planes perpendicular to the axes of the Cartesian coordinate system. For instance, a plane parallel to the $yz$-plane (perpendicular to the $x$-axis) which intesects the $x$-axis at 1, can be written as\n", "\n", "$$x = 1$$" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(-24.0, -50.0, -50.0), p2=(26.0, 50.0, 50.0)), n=(1, 2, 2), attributes: (unit: m, fourierspace: False, isplane: True, planeaxis: 0, point: 1, axis1: 1, axis2: 2)), dim=3, components: (x, y, z))" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.plane(x=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to cut through the middle of the mesh, we do not need to provide a particular value for a coordinate." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(-25.0, -50.0, -50.0), p2=(25.0, 50.0, 50.0)), n=(1, 2, 2), attributes: (unit: m, fourierspace: False, isplane: True, planeaxis: 0, point: 0.0, axis1: 1, axis2: 2)), dim=3, components: (x, y, z))" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.plane(\"x\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cascading the operations\n", "\n", "Let us say we want to compute the average of an $x$ component of the field on the plane $y=10$. In order to do that, we can cascade several operation in a single line." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.plane(y=10).x.average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This gives the same result as for instance" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field.x.plane(y=10).average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Complex fields\n", "\n", "`discretisedfield` supports complex-valued fields." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "cfield = df.Field(mesh, dim=3, value=(1 + 1.5j, 2, 3j))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can extract `real` and `imaginary` part." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 2.0, 0.0)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cfield.real((0, 0, 0))" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.5, 0.0, 3.0)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cfield.imag((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly we get `real` and `imaginary` parts of individual components." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cfield.x.real((0, 0, 0))" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.5" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cfield.x.imag((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Complex conjugate." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((1-1.5j), (2-0j), -3j)" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cfield.conjugate((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Phase in the complex plane." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(0.982793723247329, 0.0, 1.5707963267948966)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cfield.phase((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Algebra operations\n", "\n", "Let us define two fields:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "region = df.Region(p1=(0, 0, 0), p2=(10e-9, 10e-9, 10e-9))\n", "mesh = df.Mesh(region=region, n=(10, 10, 10))\n", "\n", "f1 = df.Field(mesh, dim=3, value=(1, 1, 0))\n", "f2 = df.Field(mesh, dim=3, value=(2, 1, 3))" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 1.0, 0.0)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.average" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2.0, 1.0, 3.0)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f2.average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `+` operation" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1 + f2" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3.0, 2.0, 3.0)" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(f1 + f2).average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `-` operation" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1 - f2" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-1.0, 0.0, -3.0)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(f1 - f2).average" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `*` operation\n", "\n", "Basic multiplication is not defined between vector fields. In that case, we perform either dot or cross product, which we are going to discuss later." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "Cannot apply operator * on self.dim=3 and other.dim=3 fields.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Input \u001b[0;32mIn [42]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mf1\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mf2\u001b[49m\n", "File \u001b[0;32m~/PhD/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:1331\u001b[0m, in \u001b[0;36mField.__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 1328\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m other\u001b[38;5;241m.\u001b[39mdim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m:\n\u001b[1;32m 1329\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCannot apply operator * on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1330\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mand \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mother\u001b[38;5;241m.\u001b[39mdim\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m fields.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m-> 1331\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(msg)\n\u001b[1;32m 1332\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmesh \u001b[38;5;241m!=\u001b[39m other\u001b[38;5;241m.\u001b[39mmesh:\n\u001b[1;32m 1333\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCannot apply operator * on fields \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1334\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdefined on different meshes.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: Cannot apply operator * on self.dim=3 and other.dim=3 fields." ] } ], "source": [ "f1 * f2 # both are vector fields" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scalar with vector field:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.x * f2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scalar with vector field:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.x * f2.y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `/` operation" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "Cannot apply ** operator on self.dim=3 field.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Input \u001b[0;32mIn [45]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mf1\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mf2\u001b[49m\n", "File \u001b[0;32m~/PhD/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:1424\u001b[0m, in \u001b[0;36mField.__truediv__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 1359\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__truediv__\u001b[39m(\u001b[38;5;28mself\u001b[39m, other):\n\u001b[1;32m 1360\u001b[0m \u001b[38;5;124;03m\"\"\"Binary ``/`` operator.\u001b[39;00m\n\u001b[1;32m 1361\u001b[0m \n\u001b[1;32m 1362\u001b[0m \u001b[38;5;124;03m It can be applied between:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \n\u001b[1;32m 1423\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1424\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m \u001b[38;5;241m*\u001b[39m \u001b[43mother\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/PhD/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:1102\u001b[0m, in \u001b[0;36mField.__pow__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 1101\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCannot apply ** operator on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m field.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(msg)\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(other, numbers\u001b[38;5;241m.\u001b[39mReal):\n\u001b[1;32m 1104\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUnsupported operand type(s) for **: \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1105\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(\u001b[38;5;28mself\u001b[39m)\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(other)\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: Cannot apply ** operator on self.dim=3 field." ] } ], "source": [ "f1 / f2 # both are vector fields" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dividing vector field by a scalar field:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1 / f2.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scalar field divided by vector field is not allowed:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "Cannot apply ** operator on self.dim=3 field.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Input \u001b[0;32mIn [47]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mf2\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mf1\u001b[49m\n", "File \u001b[0;32m~/PhD/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:1424\u001b[0m, in \u001b[0;36mField.__truediv__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 1359\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__truediv__\u001b[39m(\u001b[38;5;28mself\u001b[39m, other):\n\u001b[1;32m 1360\u001b[0m \u001b[38;5;124;03m\"\"\"Binary ``/`` operator.\u001b[39;00m\n\u001b[1;32m 1361\u001b[0m \n\u001b[1;32m 1362\u001b[0m \u001b[38;5;124;03m It can be applied between:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \n\u001b[1;32m 1423\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1424\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m \u001b[38;5;241m*\u001b[39m \u001b[43mother\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/PhD/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:1102\u001b[0m, in \u001b[0;36mField.__pow__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 1101\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCannot apply ** operator on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m field.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(msg)\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(other, numbers\u001b[38;5;241m.\u001b[39mReal):\n\u001b[1;32m 1104\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUnsupported operand type(s) for **: \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1105\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(\u001b[38;5;28mself\u001b[39m)\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(other)\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: Cannot apply ** operator on self.dim=3 field." ] } ], "source": [ "f2.x / f1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `**` operator\n", "\n", "This operator is allowed only on scalar fields:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "Cannot apply ** operator on self.dim=3 field.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Input \u001b[0;32mIn [48]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mf1\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\n", "File \u001b[0;32m~/PhD/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:1102\u001b[0m, in \u001b[0;36mField.__pow__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 1101\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCannot apply ** operator on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdim\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m field.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(msg)\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(other, numbers\u001b[38;5;241m.\u001b[39mReal):\n\u001b[1;32m 1104\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUnsupported operand type(s) for **: \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1105\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(\u001b[38;5;28mself\u001b[39m)\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(other)\u001b[38;5;132;01m=}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: Cannot apply ** operator on self.dim=3 field." ] } ], "source": [ "f1**2" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.x**2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Compund operations" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "f1 += f2" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [], "source": [ "f1 -= f2" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "f1 *= f2.x" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [], "source": [ "f2 /= f2.y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vector products\n", "\n", "As the title says, these products are applied between vector fields only.\n", "\n", "### Dot product\n", "\n", "Dot product is implemented through `@` operator:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1 @ f2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Cross product\n", "\n", "Cross product between vector fields is performed using `&` operator:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 3
  • \n", "
  • components:\n", "
    • x
    • \n", "
    • y
    • \n", "
    • z
    • \n", "
    \n", "
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1 & f2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vector calculus\n", "\n", "### Directional derivative $\\left(\\frac{\\partial}{\\partial x_{i}}f\\right)$\n", "\n", "Defined on both scalar and vector fields:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 3
  • \n", "
  • components:\n", "
    • x
    • \n", "
    • y
    • \n", "
    • z
    • \n", "
    \n", "
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.derivative(\"x\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Gradient $(\\nabla f)$\n", "\n", "Defined on scalar fields:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 3
  • \n", "
  • components:\n", "
    • x
    • \n", "
    • y
    • \n", "
    • z
    • \n", "
    \n", "
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.x.grad" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Divergence $(\\nabla \\cdot f)$\n", "\n", "Defined on vector fields:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.div" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Curl $(\\nabla \\times f)$\n", "\n", "Defined on vector fields:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 3
  • \n", "
  • components:\n", "
    • x
    • \n", "
    • y
    • \n", "
    • z
    • \n", "
    \n", "
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.curl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Laplace operator $(\\nabla^{2} f)$\n", "\n", "Defined on both vector and scalar fields:" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 3
  • \n", "
  • components:\n", "
    • x
    • \n", "
    • y
    • \n", "
    • z
    • \n", "
    \n", "
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.laplace" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", "
    • \n", "
    • n = (10, 10, 10)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(10, 10, 10), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.x.laplace" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Integrals\n", "\n", "In the most recent version of `discretisedfield`, computing integrals is generalised to accomodate the calculation of different types of integrals. Instead of giving the \"theory\" behind how it was implemented, we are going to show several examples which hopefully are going to give you an idea how you can compute different integrals.\n", "\n", "Let us first create a field:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "import discretisedfield as df\n", "\n", "p1 = (0, 0, 0)\n", "p2 = (100e-9, 100e-9, 100e-9)\n", "cell = (2e-9, 2e-9, 2e-9)\n", "region = df.Region(p1=p1, p2=p2)\n", "mesh = df.Mesh(region=region, cell=cell)\n", "f = df.Field(mesh, dim=3, value=(-3, 0, 4), norm=1e6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Volume integral\n", "\n", "$$\\int_{V}\\mathbf{f}(\\mathbf{r})\\text{d}V$$" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-6.000000000017728e-16, 0.0, 8.00000000001152e-16)" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f * df.dV)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since $\\text{d}V = \\text{d}x\\text{d}y\\text{d}z$, we can compute the integral as:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-6.000000000017728e-16, 0.0, 8.00000000001152e-16)" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f * df.dx * df.dy * df.dz)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$\\int_{V}f_{x}(\\mathbf{r})\\text{d}V$$" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-6.000000000000003e-16" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.x * df.dV)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Surface integral\n", "\n", "There is `disretisedfield.dS` value which is a vector field perpendicular to the surface with magnitude equal to the area of $\\text{d}S$.\n", "\n", "$$\\int_{S}\\mathbf{f}(\\mathbf{r}) \\cdot \\text{d}\\mathbf{S}$$\n", "\n", "Like all plane-related operations, the field must be sliced." ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7.999999999999996e-09" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.plane(\"z\") @ df.dS)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, we can write $\\text{d}S = \\text{d}x\\text{d}y$ when we cut $z$-plane or we can use $|\\text{d}\\mathbf{S}|$.\n", "\n", "$$\\int_{S}f_{x}(\\mathbf{r}) \\text{d}x\\text{d}y$$" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-5.999999999999999e-09" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.x.plane(\"z\") * df.dx * df.dy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$\\int_{S}f_{x}(\\mathbf{r}) |\\text{d}\\mathbf{S}|$$" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-5.9999999999999975e-09" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.x.plane(\"z\") * abs(df.dS))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Line integrals\n", "\n", "$$\\int_{0}^{x_\\text{max}}\\mathbf{f}(\\mathbf{r}) \\text{d}x$$" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (4.8999999999999995e-08, 0.0, 0.0)
      • \n", "
      • p2 = (5.1e-08, 1e-07, 1e-07)
      • \n", "
    • \n", "
    • n = (1, 50, 50)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: True
      • \n", "
      • planeaxis: 0
      • \n", "
      • point: 5e-08
      • \n", "
      • axis1: 1
      • \n", "
      • axis2: 2
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 3
  • \n", "
  • components:\n", "
    • x
    • \n", "
    • y
    • \n", "
    • z
    • \n", "
    \n", "
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(4.8999999999999995e-08, 0.0, 0.0), p2=(5.1e-08, 1e-07, 1e-07)), n=(1, 50, 50), attributes: (unit: m, fourierspace: False, isplane: True, planeaxis: 0, point: 5e-08, axis1: 1, axis2: 2)), dim=3, components: (x, y, z))" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f * df.dx, direction=\"x\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$\\int_{0}^{y_\\text{max}}f_{x}(\\mathbf{r}) \\text{d}y$$" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0.0, 4.8999999999999995e-08, 0.0)
      • \n", "
      • p2 = (1e-07, 5.1e-08, 1e-07)
      • \n", "
    • \n", "
    • n = (50, 1, 50)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: True
      • \n", "
      • planeaxis: 1
      • \n", "
      • point: 5e-08
      • \n", "
      • axis1: 0
      • \n", "
      • axis2: 2
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0.0, 4.8999999999999995e-08, 0.0), p2=(1e-07, 5.1e-08, 1e-07)), n=(50, 1, 50), attributes: (unit: m, fourierspace: False, isplane: True, planeaxis: 1, point: 5e-08, axis1: 0, axis2: 2)), dim=1)" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.x * df.dy, direction=\"y\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Improper integrals" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$\\int_{0}^{y}\\mathbf{f}(\\mathbf{r}) \\text{d}y'$$" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-07, 1e-07, 1e-07)
      • \n", "
    • \n", "
    • n = (50, 50, 50)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-07, 1e-07, 1e-07)), n=(50, 50, 50), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.x * df.dy, direction=\"y\", improper=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example\n", "\n", "We have showed how to compute an integral when integrand is just a field. It is important to have in mind that this can be any field after some operations have been applied on it. For instance:\n", "\n", "$$\\int_{V}\\nabla\\cdot\\mathbf{f}(\\mathbf{r})\\text{d}V$$" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f.div * df.dV)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operation pipelines" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(0.0, 0.0, 0.0)" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.integral(f1.x.grad.div.grad.curl.y.grad * df.dV)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example\n", "\n", "Here we implement skyrmion number calculations using operations on fields:\n", "\n", "$$S = \\frac{1}{4\\pi} \\int \\mathbf{m} \\cdot \\left(\\frac{\\partial \\mathbf{m}}{\\partial x} \\times \\frac{\\partial \\mathbf{m}}{\\partial y}\\right) dxdy$$" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "\n", "m = field.orientation.plane(\"z\")\n", "S = df.integral(m @ (m.derivative(\"x\") & m.derivative(\"y\")) * df.dx * df.dy) / (\n", " 4 * math.pi\n", ")\n", "S" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or using Ubermag function:" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import discretisedfield.tools as dft\n", "\n", "dft.topological_charge(m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using Berg-Luescher method" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dft.topological_charge(m, method=\"berg-luescher\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Applying `numpys` universal functions\n", "All numpy universal functions can be applied to `discretisedfield.Field` objects. Below we show a different examples. For available functions please refer to the `numpy` [documentation](https://numpy.org/doc/stable/reference/ufuncs.html#available-ufuncs)." ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [], "source": [ "f1 = df.Field(mesh, dim=1, value=1)\n", "f2 = df.Field(mesh, dim=1, value=np.pi)\n", "f3 = df.Field(mesh, dim=1, value=2)" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "
    \n", " \n", "
  • Mesh\n", "
      \n", "
    • Region\n", "
        \n", "
      • p1 = (0, 0, 0)
      • \n", "
      • p2 = (1e-07, 1e-07, 1e-07)
      • \n", "
    • \n", "
    • n = (50, 50, 50)
    • \n", "
    • attributes:\n", "
        \n", "
      • unit: m
      • \n", "
      • fourierspace: False
      • \n", "
      • isplane: False
      • \n", "
      \n", "
    • \n", "
  • \n", "
  • dim = 1
  • \n", "
" ], "text/plain": [ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-07, 1e-07, 1e-07)), n=(50, 50, 50), attributes: (unit: m, fourierspace: False, isplane: False)), dim=1)" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sin(f1)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.2246467991473532e-16" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sin(f2)((0, 0, 0))" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6.141592653589793" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum((f1, f2, f3))((0, 0, 0))" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.718281828459045" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.exp(f1)((0, 0, 0))" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4.0" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.power(f3, 2)((0, 0, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other\n", "\n", "Full description of all existing functionality can be found in the [API Reference](https://ubermag.github.io/api/_autosummary/discretisedfield.Field.html)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.8.12" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }