Skip to content

Instantly share code, notes, and snippets.

@t-makaro
Created April 9, 2018 03:28
Show Gist options
  • Save t-makaro/d2ed1f9d3433a88cdc9a421489f959db to your computer and use it in GitHub Desktop.
Save t-makaro/d2ed1f9d3433a88cdc9a421489f959db to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2D FDTD simulation"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib notebook\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.animation import FuncAnimation, PillowWriter\n",
"from scipy.constants import epsilon_0, mu_0, c"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"Omega_0 = np.sqrt(mu_0/epsilon_0)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"dt = 0.1\n",
"\n",
"epsilon_r = 1\n",
"mu_r = 1\n",
"v = 1/np.sqrt(epsilon_r*mu_r)\n",
"\n",
"Period = 40*dt\n",
"\n",
"dy = dx = dt/4*np.sqrt(2)\n",
"a, b = -2, 2\n",
"\n",
"x = np.arange(a, b+dx/2, dx)\n",
"y = np.arange(a, b+dy/2, dy)\n",
"t = np.arange(0, 36+dt/2, dt)\n",
"\n",
"origin = x.shape[0]//2+1 # iff a==b\n",
"Ez = np.zeros_like(np.meshgrid(x, y, t)[0])\n",
"Hy = Ez.copy()\n",
"Hx = Ez.copy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We modify $\\epsilon_r$ and $\\mu_r$ instead of $\\Omega_0$ so that we can keep the faster vectorized code AND prevent the universe from exploding. "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"X, Y = np.meshgrid(x, y)\n",
"\n",
"Mu_r = np.ones_like(X)\n",
"Mu_r[np.logical_and(Y>1/X, X>0)] = 1/3\n",
"Mu_r[np.logical_and(Y+dy<1/(X+dx), X+dx<0)] = 1/3\n",
"\n",
"Epsilon_r = np.ones_like(X)\n",
"Epsilon_r[np.logical_and(Y>1/X, X>0)] = 3\n",
"Epsilon_r[np.logical_and(Y<1/X, X<0)] = 3\n",
"\n",
"# plt.pcolormesh(x,y,Mu_r)\n",
"# plt.title('The Dielectric Location')\n",
"# plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"I define the sinusoidal source term over 4 points to avoid jaggedness, and I precalculated an array for the source to make the computation 10x faster. Still additive."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"source_m = np.zeros_like(Ez)\n",
"source_m[origin-1:origin+1, origin-1:origin+1, t<Period] = np.sin(2*np.pi*t[t<Period]/Period)\n",
"#source_m[origin-1:origin+1, origin-1:origin+1, :] = np.sin(2*np.pi*t[:]/Period)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Wall time: 679 ms\n"
]
}
],
"source": [
"%%time\n",
"for t_i in range(1, len(t)): \n",
" Hy[:-1,:-1,t_i] = Hy[:-1,:-1,t_i-1] + 1/Mu_r[:-1,:-1]/Omega_0*(\n",
" Ez[1:,:-1,t_i-1]-Ez[:-1,:-1,t_i-1])/np.sqrt(2)\n",
" Hx[:-1,:-1,t_i] = Hx[:-1,:-1,t_i-1] - 1/Mu_r[:-1,:-1]/Omega_0*(\n",
" Ez[:-1,1:,t_i-1]-Ez[:-1,:-1,t_i-1])/np.sqrt(2)\n",
" \n",
" Ez[1:-1, 1:-1, t_i] = (Ez[1:-1, 1:-1, t_i-1] + 1/Epsilon_r[1:-1,1:-1]*Omega_0*(\n",
" (Hy[1:-1, 1:-1, t_i]-Hy[:-2, 1:-1, t_i])-(Hx[1:-1, 1:-1, t_i]-Hx[1:-1,:-2,t_i]))\n",
" /np.sqrt(2)+source_m[1:-1, 1:-1, t_i])"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig = plt.figure()\n",
"ax = plt.gca()\n",
"ticks = np.arange(-2,2.2,.5)\n",
"def animate(i):\n",
" ax.clear()\n",
" plt.pcolormesh(x, y, Ez[:,:,i], vmin=-.4, vmax=.4, cmap='seismic')\n",
" plt.title(f'Normalized $E$-Field vs Position at $t={t[i]/4:.2f}T$')\n",
" plt.xlabel('Distance ($x/(cT$))')\n",
" plt.ylabel('Distance ($y/(cT$))')\n",
" ax.set_aspect('equal')\n",
" plt.plot(np.arange(.51,2.,.01),1/np.arange(.51,2.,.01),'k')\n",
" plt.plot(np.arange(-2,-.5,.01),1/np.arange(-2,-.5,.01),'k')\n",
" plt.xticks(ticks)\n",
" plt.yticks(ticks)\n",
"\n",
"animate(0)\n",
"cbar = plt.colorbar()\n",
"cbar.set_label(r'$\\frac{E_z}{E_0}$', size='large')\n",
"anim = FuncAnimation(fig, animate, frames=range(len(t)), blit=True)\n",
"#anim.save('fields_dielectric.gif', writer=PillowWriter(fps=24))\n",
"#anim.save('fields_dielectric.mp4', writer='ffmpeg', fps=24, dpi=200)\n",
"plt.show()"
]
},
{
"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.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment