{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "This morning, I saw a cool looking tweet on sci-twitter. Since it's about waves and it looks very nice, I want to try to reproduce it and share the results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's the tweet:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The way I understand what's going on, we need the following building blocks to get to make an animation that looks like the one in the tweet:\n", "\n", "- single cylindrical wave source on a grid\n", "- line of cylindrical wave sources on a grid\n", "- take into account phase delays to allow for focusing and beam deviation\n", "\n", "Let's get started." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Cylindrical waves on a grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In its simplest form, we can use a Green's function approach and just evaluate the solution of a single line source. Based on the analytical solution for the 3D Helmholtz equation (as can be read in [this reference](https://users.flatironinstitute.org/~ahb/notes/waveequation.pdf)), we can write\n", "\n", "$$\n", "f(r) = \\frac{e^{ikr}}{4πr} \n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can write some straightforward code to evaluate this on a grid, that I choose to be the same than in the tweet." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "number of points per wavelenght: 20.0\n" ] } ], "source": [ "import numpy as np\n", "\n", "wavelength = 1.\n", "n_lambda = 20.\n", "n_points = 401\n", "dx = n_lambda * wavelength / (n_points - 1)\n", "k = 2 * np.pi / wavelength\n", "print(f\"number of points per wavelenght: {wavelength/dx}\")\n", "x = np.linspace(-n_lambda//2 * wavelength, n_lambda//2 * wavelength, num=n_points)\n", "y = np.linspace(0, n_lambda * wavelength, num=n_points)\n", "X, Y = np.meshgrid(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's write a function that allows us to compute the field amplitude." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def compute_amplitude_from_source_point(source_location, X, Y, k):\n", " x0, y0 = source_location\n", " R = np.sqrt((X - x0)**2 + (Y - y0)**2)\n", " amp = np.exp(1j * k * R) \n", " amp[np.isinf(amp)] = 0.\n", " return np.real(amp)\n", "\n", "amp = compute_amplitude_from_source_point((0., 0.), X, Y, k)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "\n", "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " var force = true;\n", "\n", " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", " root._bokeh_onload_callbacks = [];\n", " root._bokeh_is_loading = undefined;\n", " }\n", "\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", " if (root._bokeh_is_loading > 0) {\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " }\n", " if (js_urls == null || js_urls.length === 0) {\n", " run_callbacks();\n", " return null;\n", " }\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " root._bokeh_is_loading = css_urls.length + js_urls.length;\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", "\n", " function on_error() {\n", " console.error(\"failed to load \" + url);\n", " }\n", "\n", " for (var i = 0; i < css_urls.length; i++) {\n", " var url = css_urls[i];\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " }\n", "\n", " if (window.requirejs) {\n", " require([], function() {\n", " run_callbacks();\n", " })\n", " } else {\n", " var skip = [];\n", " for (var i = 0; i < js_urls.length; i++) {\n", " var url = js_urls[i];\n", " if (skip.indexOf(url) >= 0) { on_load(); continue; }\n", " var element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " var js_urls = [];\n", " var css_urls = [];\n", "\n", " var inline_js = [\n", " function(Bokeh) {\n", " inject_raw_css(\".widget-box {\\n\\tmin-height: 20px;\\n\\tbackground-color: #f5f5f5;\\n\\tborder: 1px solid #e3e3e3 !important;\\n\\tborder-radius: 4px;\\n\\t-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.05);\\n\\tbox-shadow: inset 0 1px 1px rgba(0,0,0,.05);\\n\\toverflow-x: hidden;\\n\\toverflow-y: hidden;\\n}\\n\\n.scrollable {\\n overflow: scroll;\\n}\\n\\nprogress {\\n\\tappearance: none;\\n\\t-moz-appearance: none;\\n\\t-webkit-appearance: none;\\n\\n\\tborder: none;\\n\\theight: 20px;\\n\\tbackground-color: whiteSmoke;\\n\\tborder-radius: 3px;\\n\\tbox-shadow: 0 2px 3px rgba(0,0,0,.5) inset;\\n\\tcolor: royalblue;\\n\\tposition: relative;\\n\\tmargin: 0 0 1.5em;\\n}\\n\\nprogress[value]::-webkit-progress-bar {\\n\\tbackground-color: whiteSmoke;\\n\\tborder-radius: 3px;\\n\\tbox-shadow: 0 2px 3px rgba(0,0,0,.5) inset;\\n}\\n\\nprogress[value]::-webkit-progress-value {\\n\\tposition: relative;\\n\\n\\tbackground-size: 35px 20px, 100% 100%, 100% 100%;\\n\\tborder-radius:3px;\\n}\\n\\nprogress.active:not([value])::before {\\n\\tbackground-position: 10%;\\n\\tanimation-name: stripes;\\n\\tanimation-duration: 3s;\\n\\tanimation-timing-function: linear;\\n\\tanimation-iteration-count: infinite;\\n}\\n\\nprogress[value]::-moz-progress-bar {\\n\\tbackground-size: 35px 20px, 100% 100%, 100% 100%;\\n\\tborder-radius:3px;\\n}\\n\\nprogress:not([value])::-moz-progress-bar {\\n\\tborder-radius:3px;\\n\\tbackground:\\n\\tlinear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, 0.2) 33%, rgba(0, 0, 0, 0.2) 66%, transparent 66%) left/2.5em 1.5em;\\n\\n}\\n\\nprogress.active:not([value])::-moz-progress-bar {\\n\\tbackground-position: 10%;\\n\\tanimation-name: stripes;\\n\\tanimation-duration: 3s;\\n\\tanimation-timing-function: linear;\\n\\tanimation-iteration-count: infinite;\\n}\\n\\nprogress.active:not([value])::-webkit-progress-bar {\\n\\tbackground-position: 10%;\\n\\tanimation-name: stripes;\\n\\tanimation-duration: 3s;\\n\\tanimation-timing-function: linear;\\n\\tanimation-iteration-count: infinite;\\n}\\n\\nprogress.primary[value]::-webkit-progress-value { background-color: #007bff; }\\nprogress.primary:not([value])::before { background-color: #007bff; }\\nprogress.primary:not([value])::-webkit-progress-bar { background-color: #007bff; }\\nprogress.primary::-moz-progress-bar { background-color: #007bff; }\\n\\nprogress.secondary[value]::-webkit-progress-value { background-color: #6c757d; }\\nprogress.secondary:not([value])::before { background-color: #6c757d; }\\nprogress.secondary:not([value])::-webkit-progress-bar { background-color: #6c757d; }\\nprogress.secondary::-moz-progress-bar { background-color: #6c757d; }\\n\\nprogress.success[value]::-webkit-progress-value { background-color: #28a745; }\\nprogress.success:not([value])::before { background-color: #28a745; }\\nprogress.success:not([value])::-webkit-progress-bar { background-color: #28a745; }\\nprogress.success::-moz-progress-bar { background-color: #28a745; }\\n\\nprogress.danger[value]::-webkit-progress-value { background-color: #dc3545; }\\nprogress.danger:not([value])::before { background-color: #dc3545; }\\nprogress.danger:not([value])::-webkit-progress-bar { background-color: #dc3545; }\\nprogress.danger::-moz-progress-bar { background-color: #dc3545; }\\n\\nprogress.warning[value]::-webkit-progress-value { background-color: #ffc107; }\\nprogress.warning:not([value])::before { background-color: #ffc107; }\\nprogress.warning:not([value])::-webkit-progress-bar { background-color: #ffc107; }\\nprogress.warning::-moz-progress-bar { background-color: #ffc107; }\\n\\nprogress.info[value]::-webkit-progress-value { background-color: #17a2b8; }\\nprogress.info:not([value])::before { background-color: #17a2b8; }\\nprogress.info:not([value])::-webkit-progress-bar { background-color: #17a2b8; }\\nprogress.info::-moz-progress-bar { background-color: #17a2b8; }\\n\\nprogress.light[value]::-webkit-progress-value { background-color: #f8f9fa; }\\nprogress.light:not([value])::before { background-color: #f8f9fa; }\\nprogress.light:not([value])::-webkit-progress-bar { background-color: #f8f9fa; }\\nprogress.light::-moz-progress-bar { background-color: #f8f9fa; }\\n\\nprogress.dark[value]::-webkit-progress-value { background-color: #343a40; }\\nprogress.dark:not([value])::-webkit-progress-bar { background-color: #343a40; }\\nprogress.dark:not([value])::before { background-color: #343a40; }\\nprogress.dark::-moz-progress-bar { background-color: #343a40; }\\n\\nprogress:not([value])::-webkit-progress-bar {\\n\\tborder-radius: 3px;\\n\\tbackground:\\n\\tlinear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, 0.2) 33%, rgba(0, 0, 0, 0.2) 66%, transparent 66%) left/2.5em 1.5em;\\n}\\nprogress:not([value])::before {\\n\\tcontent:\\\" \\\";\\n\\tposition:absolute;\\n\\theight: 20px;\\n\\ttop:0;\\n\\tleft:0;\\n\\tright:0;\\n\\tbottom:0;\\n\\tborder-radius: 3px;\\n\\tbackground:\\n\\tlinear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, 0.2) 33%, rgba(0, 0, 0, 0.2) 66%, transparent 66%) left/2.5em 1.5em;\\n}\\n\\n@keyframes stripes {\\n from {background-position: 0%}\\n to {background-position: 100%}\\n}\");\n", " },\n", " function(Bokeh) {\n", " inject_raw_css(\".codehilite .hll { background-color: #ffffcc }\\n.codehilite { background: #f8f8f8; }\\n.codehilite .c { color: #408080; font-style: italic } /* Comment */\\n.codehilite .err { border: 1px solid #FF0000 } /* Error */\\n.codehilite .k { color: #008000; font-weight: bold } /* Keyword */\\n.codehilite .o { color: #666666 } /* Operator */\\n.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\\n.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */\\n.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */\\n.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\\n.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */\\n.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */\\n.codehilite .gd { color: #A00000 } /* Generic.Deleted */\\n.codehilite .ge { font-style: italic } /* Generic.Emph */\\n.codehilite .gr { color: #FF0000 } /* Generic.Error */\\n.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */\\n.codehilite .gi { color: #00A000 } /* Generic.Inserted */\\n.codehilite .go { color: #888888 } /* Generic.Output */\\n.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\\n.codehilite .gs { font-weight: bold } /* Generic.Strong */\\n.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\\n.codehilite .gt { color: #0044DD } /* Generic.Traceback */\\n.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\\n.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\\n.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\\n.codehilite .kp { color: #008000 } /* Keyword.Pseudo */\\n.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\\n.codehilite .kt { color: #B00040 } /* Keyword.Type */\\n.codehilite .m { color: #666666 } /* Literal.Number */\\n.codehilite .s { color: #BA2121 } /* Literal.String */\\n.codehilite .na { color: #7D9029 } /* Name.Attribute */\\n.codehilite .nb { color: #008000 } /* Name.Builtin */\\n.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */\\n.codehilite .no { color: #880000 } /* Name.Constant */\\n.codehilite .nd { color: #AA22FF } /* Name.Decorator */\\n.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */\\n.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\\n.codehilite .nf { color: #0000FF } /* Name.Function */\\n.codehilite .nl { color: #A0A000 } /* Name.Label */\\n.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\\n.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */\\n.codehilite .nv { color: #19177C } /* Name.Variable */\\n.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\\n.codehilite .w { color: #bbbbbb } /* Text.Whitespace */\\n.codehilite .mb { color: #666666 } /* Literal.Number.Bin */\\n.codehilite .mf { color: #666666 } /* Literal.Number.Float */\\n.codehilite .mh { color: #666666 } /* Literal.Number.Hex */\\n.codehilite .mi { color: #666666 } /* Literal.Number.Integer */\\n.codehilite .mo { color: #666666 } /* Literal.Number.Oct */\\n.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */\\n.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */\\n.codehilite .sc { color: #BA2121 } /* Literal.String.Char */\\n.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */\\n.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\\n.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */\\n.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\\n.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */\\n.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\\n.codehilite .sx { color: #008000 } /* Literal.String.Other */\\n.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */\\n.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */\\n.codehilite .ss { color: #19177C } /* Literal.String.Symbol */\\n.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */\\n.codehilite .fm { color: #0000FF } /* Name.Function.Magic */\\n.codehilite .vc { color: #19177C } /* Name.Variable.Class */\\n.codehilite .vg { color: #19177C } /* Name.Variable.Global */\\n.codehilite .vi { color: #19177C } /* Name.Variable.Instance */\\n.codehilite .vm { color: #19177C } /* Name.Variable.Magic */\\n.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */\\n\\n.markdown h1 { margin-block-start: 0.34em }\\n.markdown h2 { margin-block-start: 0.42em }\\n.markdown h3 { margin-block-start: 0.5em }\\n.markdown h4 { margin-block-start: 0.67em }\\n.markdown h5 { margin-block-start: 0.84em }\\n.markdown h6 { margin-block-start: 1.17em }\\n.markdown ul { padding-inline-start: 2em }\\n.markdown ol { padding-inline-start: 2em }\\n.markdown strong { font-weight: 600 }\\n.markdown a { color: -webkit-link }\\n.markdown a { color: -moz-hyperlinkText }\\n\");\n", " },\n", " function(Bokeh) {\n", " inject_raw_css(\".json-formatter-row {\\n font-family: monospace;\\n}\\n.json-formatter-row,\\n.json-formatter-row a,\\n.json-formatter-row a:hover {\\n color: black;\\n text-decoration: none;\\n}\\n.json-formatter-row .json-formatter-row {\\n margin-left: 1rem;\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty {\\n opacity: 0.5;\\n margin-left: 1rem;\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty:after {\\n display: none;\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-object:after {\\n content: \\\"No properties\\\";\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-array:after {\\n content: \\\"[]\\\";\\n}\\n.json-formatter-row .json-formatter-string,\\n.json-formatter-row .json-formatter-stringifiable {\\n color: green;\\n white-space: pre;\\n word-wrap: break-word;\\n}\\n.json-formatter-row .json-formatter-number {\\n color: blue;\\n}\\n.json-formatter-row .json-formatter-boolean {\\n color: red;\\n}\\n.json-formatter-row .json-formatter-null {\\n color: #855A00;\\n}\\n.json-formatter-row .json-formatter-undefined {\\n color: #ca0b69;\\n}\\n.json-formatter-row .json-formatter-function {\\n color: #FF20ED;\\n}\\n.json-formatter-row .json-formatter-date {\\n background-color: rgba(0, 0, 0, 0.05);\\n}\\n.json-formatter-row .json-formatter-url {\\n text-decoration: underline;\\n color: blue;\\n cursor: pointer;\\n}\\n.json-formatter-row .json-formatter-bracket {\\n color: blue;\\n}\\n.json-formatter-row .json-formatter-key {\\n color: #00008B;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-row .json-formatter-toggler-link {\\n cursor: pointer;\\n}\\n.json-formatter-row .json-formatter-toggler {\\n line-height: 1.2rem;\\n font-size: 0.7rem;\\n vertical-align: middle;\\n opacity: 0.6;\\n cursor: pointer;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-row .json-formatter-toggler:after {\\n display: inline-block;\\n transition: transform 100ms ease-in;\\n content: \\\"\\\\25BA\\\";\\n}\\n.json-formatter-row > a > .json-formatter-preview-text {\\n opacity: 0;\\n transition: opacity 0.15s ease-in;\\n font-style: italic;\\n}\\n.json-formatter-row:hover > a > .json-formatter-preview-text {\\n opacity: 0.6;\\n}\\n.json-formatter-row.json-formatter-open > .json-formatter-toggler-link .json-formatter-toggler:after {\\n transform: rotate(90deg);\\n}\\n.json-formatter-row.json-formatter-open > .json-formatter-children:after {\\n display: inline-block;\\n}\\n.json-formatter-row.json-formatter-open > a > .json-formatter-preview-text {\\n display: none;\\n}\\n.json-formatter-row.json-formatter-open.json-formatter-empty:after {\\n display: block;\\n}\\n.json-formatter-dark.json-formatter-row {\\n font-family: monospace;\\n}\\n.json-formatter-dark.json-formatter-row,\\n.json-formatter-dark.json-formatter-row a,\\n.json-formatter-dark.json-formatter-row a:hover {\\n color: white;\\n text-decoration: none;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-row {\\n margin-left: 1rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty {\\n opacity: 0.5;\\n margin-left: 1rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty:after {\\n display: none;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-object:after {\\n content: \\\"No properties\\\";\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-array:after {\\n content: \\\"[]\\\";\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-string,\\n.json-formatter-dark.json-formatter-row .json-formatter-stringifiable {\\n color: #31F031;\\n white-space: pre;\\n word-wrap: break-word;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-number {\\n color: #66C2FF;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-boolean {\\n color: #EC4242;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-null {\\n color: #EEC97D;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-undefined {\\n color: #ef8fbe;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-function {\\n color: #FD48CB;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-date {\\n background-color: rgba(255, 255, 255, 0.05);\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-url {\\n text-decoration: underline;\\n color: #027BFF;\\n cursor: pointer;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-bracket {\\n color: #9494FF;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-key {\\n color: #23A0DB;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-toggler-link {\\n cursor: pointer;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-toggler {\\n line-height: 1.2rem;\\n font-size: 0.7rem;\\n vertical-align: middle;\\n opacity: 0.6;\\n cursor: pointer;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-toggler:after {\\n display: inline-block;\\n transition: transform 100ms ease-in;\\n content: \\\"\\\\25BA\\\";\\n}\\n.json-formatter-dark.json-formatter-row > a > .json-formatter-preview-text {\\n opacity: 0;\\n transition: opacity 0.15s ease-in;\\n font-style: italic;\\n}\\n.json-formatter-dark.json-formatter-row:hover > a > .json-formatter-preview-text {\\n opacity: 0.6;\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open > .json-formatter-toggler-link .json-formatter-toggler:after {\\n transform: rotate(90deg);\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open > .json-formatter-children:after {\\n display: inline-block;\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open > a > .json-formatter-preview-text {\\n display: none;\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open.json-formatter-empty:after {\\n display: block;\\n}\\n\");\n", " },\n", " function(Bokeh) {\n", " inject_raw_css(\"table.panel-df {\\n margin-left: auto;\\n margin-right: auto;\\n border: none;\\n border-collapse: collapse;\\n border-spacing: 0;\\n color: black;\\n font-size: 12px;\\n table-layout: fixed;\\n width: 100%;\\n}\\n\\n.panel-df tr, th, td {\\n text-align: right;\\n vertical-align: middle;\\n padding: 0.5em 0.5em !important;\\n line-height: normal;\\n white-space: normal;\\n max-width: none;\\n border: none;\\n}\\n\\n.panel-df tbody {\\n display: table-row-group;\\n vertical-align: middle;\\n border-color: inherit;\\n}\\n\\n.panel-df tbody tr:nth-child(odd) {\\n background: #f5f5f5;\\n}\\n\\n.panel-df thead {\\n border-bottom: 1px solid black;\\n vertical-align: bottom;\\n}\\n\\n.panel-df tr:hover {\\n background: lightblue !important;\\n cursor: pointer;\\n}\\n\");\n", " },\n", " function(Bokeh) {\n", " /* BEGIN bokeh.min.js */\n", " /*!\n", " * Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors\n", " * All rights reserved.\n", " * \n", " * Redistribution and use in source and binary forms, with or without modification,\n", " * are permitted provided that the following conditions are met:\n", " * \n", " * Redistributions of source code must retain the above copyright notice,\n", " * this list of conditions and the following disclaimer.\n", " * \n", " * Redistributions in binary form must reproduce the above copyright notice,\n", " * this list of conditions and the following disclaimer in the documentation\n", " * and/or other materials provided with the distribution.\n", " * \n", " * Neither the name of Anaconda nor the names of any contributors\n", " * may be used to endorse or promote products derived from this software\n", " * without specific prior written permission.\n", " * \n", " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n", " * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n", " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n", " * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n", " * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n", " * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n", " * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n", " * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n", " * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n", " * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n", " * THE POSSIBILITY OF SUCH DAMAGE.\n", " */\n", " (function(root, factory) {\n", " root[\"Bokeh\"] = factory();\n", " })(this, function() {\n", " var define;\n", " var parent_require = typeof require === \"function\" && require\n", " return (function(modules, entry, aliases, externals) {\n", " if (aliases === undefined) aliases = {};\n", " if (externals === undefined) externals = {};\n", "\n", " var cache = {};\n", "\n", " var normalize = function(name) {\n", " if (typeof name === \"number\")\n", " return name;\n", "\n", " if (name === \"bokehjs\")\n", " return entry;\n", "\n", " var prefix = \"@bokehjs/\"\n", " if (name.slice(0, prefix.length) === prefix)\n", " name = name.slice(prefix.length)\n", "\n", " var alias = aliases[name]\n", " if (alias != null)\n", " return alias;\n", "\n", " var trailing = name.length > 0 && name[name.lenght-1] === \"/\";\n", " var index = aliases[name + (trailing ? \"\" : \"/\") + \"index\"];\n", " if (index != null)\n", " return index;\n", "\n", " return name;\n", " }\n", "\n", " var require = function(name) {\n", " var mod = cache[name];\n", " if (!mod) {\n", " var id = normalize(name);\n", "\n", " mod = cache[id];\n", " if (!mod) {\n", " if (!modules[id]) {\n", " if (externals[id] === false || (externals[id] == true && parent_require)) {\n", " try {\n", " mod = {exports: externals[id] ? parent_require(id) : {}};\n", " cache[id] = cache[name] = mod;\n", " return mod.exports;\n", " } catch (e) {}\n", " }\n", "\n", " var err = new Error(\"Cannot find module '\" + name + \"'\");\n", " err.code = 'MODULE_NOT_FOUND';\n", " throw err;\n", " }\n", "\n", " mod = {exports: {}};\n", " cache[id] = cache[name] = mod;\n", " modules[id].call(mod.exports, require, mod, mod.exports);\n", " } else\n", " cache[name] = mod;\n", " }\n", "\n", " return mod.exports;\n", " }\n", "\n", " var main = require(entry);\n", " main.require = require;\n", "\n", " if (typeof Proxy !== \"undefined\") {\n", " // allow Bokeh.loader[\"@bokehjs/module/name\"] syntax\n", " main.loader = new Proxy({}, {\n", " get: function(_obj, module) {\n", " return require(module);\n", " }\n", " });\n", " }\n", "\n", " main.register_plugin = function(plugin_modules, plugin_entry, plugin_aliases, plugin_externals) {\n", " if (plugin_aliases === undefined) plugin_aliases = {};\n", " if (plugin_externals === undefined) plugin_externals = {};\n", "\n", " for (var name in plugin_modules) {\n", " modules[name] = plugin_modules[name];\n", " }\n", "\n", " for (var name in plugin_aliases) {\n", " aliases[name] = plugin_aliases[name];\n", " }\n", "\n", " for (var name in plugin_externals) {\n", " externals[name] = plugin_externals[name];\n", " }\n", "\n", " var plugin = require(plugin_entry);\n", "\n", " for (var name in plugin) {\n", " main[name] = plugin[name];\n", " }\n", "\n", " return plugin;\n", " }\n", "\n", " return main;\n", " })\n", " ([\n", " function _(e,t,_){Object.defineProperty(_,\"__esModule\",{value:!0}),e(1).__exportStar(e(2),_)},\n", " function _(t,e,n){\n", " /*! *****************************************************************************\n", " Copyright (c) Microsoft Corporation. All rights reserved.\n", " Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use\n", " this file except in compliance with the License. You may obtain a copy of the\n", " License at http://www.apache.org/licenses/LICENSE-2.0\n", " \n", " THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n", " KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\n", " WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\n", " MERCHANTABLITY OR NON-INFRINGEMENT.\n", " \n", " See the Apache Version 2.0 License for specific language governing permissions\n", " and limitations under the License.\n", " ***************************************************************************** */\n", " Object.defineProperty(n,\"__esModule\",{value:!0});var r=function(t,e){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function o(t){var e=\"function\"==typeof Symbol&&Symbol.iterator,n=e&&t[e],r=0;if(n)return n.call(t);if(t&&\"number\"==typeof t.length)return{next:function(){return t&&r>=t.length&&(t=void 0),{value:t&&t[r++],done:!t}}};throw new TypeError(e?\"Object is not iterable.\":\"Symbol.iterator is not defined.\")}function a(t,e){var n=\"function\"==typeof Symbol&&t[Symbol.iterator];if(!n)return t;var r,o,a=n.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(r=a.next()).done;)i.push(r.value)}catch(t){o={error:t}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}return i}function i(t){return this instanceof i?(this.v=t,this):new i(t)}n.__extends=function(t,e){function n(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)},n.__assign=function(){return n.__assign=Object.assign||function(t){for(var e,n=1,r=arguments.length;n#PhysicsFactlet (220)
— Jacopo Bertolotti (@j_bertolotti) April 21, 2020
Wavefront shaping: If you can control the relative phase of a number of point emitters, you can control the shape of your propagating wave.
(Shown: plane wave, focus, and Airy beam) pic.twitter.com/5QN5e1xZn2
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*This post was entirely written using the Jupyter Notebook. Its content is BSD-licensed. You can see a static view or download this notebook with the help of nbviewer at [20200422_PhasedArrayAnimation.ipynb](http://nbviewer.ipython.org/urls/raw.github.com/flothesof/posts/master/20200422_PhasedArrayAnimation.ipynb).*" ] } ], "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.7.6" } }, "nbformat": 4, "nbformat_minor": 4 }I appreciated this animation so much that I tried to recreate (and slightly modify) it with my own set of tools! #python #matplotlib @HoloViews Thanks @j_bertolotti https://t.co/Fg7dQZhSjH pic.twitter.com/EHWevmsOxN
— Florian Le Bourdais (@frolianlb) April 22, 2020