diff --git a/src/NaBBODES b/src/NaBBODES
deleted file mode 160000
index abbd276..0000000
--- a/src/NaBBODES
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit abbd276623a01c2ea95c089190def6d66478bac5
diff --git a/src/NaBBODES/LICENSE b/src/NaBBODES/LICENSE
new file mode 100755
index 0000000..abf3590
--- /dev/null
+++ b/src/NaBBODES/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 D. Karamitros
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/NaBBODES/RKF/0-test/Adaptive-Runge-Kutta.ipynb b/src/NaBBODES/RKF/0-test/Adaptive-Runge-Kutta.ipynb
new file mode 100755
index 0000000..42a89b7
--- /dev/null
+++ b/src/NaBBODES/RKF/0-test/Adaptive-Runge-Kutta.ipynb
@@ -0,0 +1,2303 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Adaptive-Runge–Kutta\n",
+ "\n",
+ "Compile, run, and plot the result from RKF.cpp"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import subprocess\n",
+ "import sys\n",
+ "\n",
+ "import os\n",
+ "\n",
+ "import time"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "import matplotlib\n",
+ "#matplotlib.use('WebAgg')\n",
+ "#matplotlib.use('Qt4Cairo')\n",
+ "#matplotlib.use('Qt5Cairo')\n",
+ "matplotlib.use('nbAgg')\n",
+ "import matplotlib.pyplot as plt\n",
+ "plt.rcParams['font.family']='serif'\n",
+ "plt.rcParams['font.size']=10\n",
+ "plt.rcParams['mathtext.fontset']='stixsans'\n",
+ "\n",
+ "\n",
+ "from scipy.integrate import odeint\n",
+ "from scipy.integrate import RK45 #this is DP45 as the one I use\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "os.chdir('..')\n",
+ "os.system(r'make')\n",
+ "os.chdir('0-test')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "time: 0.014755487442016602 s\n"
+ ]
+ }
+ ],
+ "source": [
+ "time0=time.time()\n",
+ "\n",
+ "output=subprocess.check_output([\"../RKF.run\"]).decode(sys.stdout.encoding).split(\"\\n\")\n",
+ "\n",
+ "print(\"time: {:10} s\".format( time.time()-time0) )\n",
+ "\n",
+ "solution=np.array([ (i.split(' '))[:-1] for i in output[:-1] ] ,np.float64)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "t=solution[:,0]\n",
+ "y1=solution[:,1]\n",
+ "y2=solution[:,2]\n",
+ "y3=solution[:,3]\n",
+ "\n",
+ "\n",
+ "err1=solution[:,4]\n",
+ "err2=solution[:,5]\n",
+ "err3=solution[:,6]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def f(t,y):\n",
+ " lhs=np.zeros(3)\n",
+ " lhs[0]=-20*y[0]*pow(t,2) ;\n",
+ " lhs[1]=5*y[0]*pow(t,2)+2*(-pow( y[1],2 )+pow( y[2],2 ) )*pow(t,1);\n",
+ " lhs[2]=15*y[0]*pow(t,2)+2*(pow( y[1],2 )-pow( y[2],2 ) )*pow(t,1);\n",
+ " return lhs"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# ?RK45"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "time: 0.5984628200531006 s\n"
+ ]
+ }
+ ],
+ "source": [
+ "sol_py=RK45(f,0,[y1[0],y2[0],y3[0]],t[-1],rtol=1e-8,atol=1e-8)\n",
+ "\n",
+ "time0=time.time()\n",
+ "\n",
+ "y_py=[]\n",
+ "t_py=[]\n",
+ "while sol_py.status=='running' :\n",
+ " sol_py.step()\n",
+ " y_py.append(sol_py.y)\n",
+ " t_py.append(sol_py.t)\n",
+ "# print(sol_py.step_size,sol_py.t)\n",
+ "y_py=np.array(y_py)\n",
+ "\n",
+ "print(\"time: {:10} s\".format( time.time()-time0) )\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def g(y,t):\n",
+ " return f(t,y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "time: 0.0075833797454833984 s\n"
+ ]
+ }
+ ],
+ "source": [
+ "time0=time.time()\n",
+ "sol_ode=odeint(g,y_py[0],t_py )\n",
+ "print(\"time: {:10} s\".format( time.time()-time0) )"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "/* global mpl */\n",
+ "window.mpl = {};\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(\n",
+ " '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",
+ "\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 = document.createElement('div');\n",
+ " this.root.setAttribute('style', 'display: inline-block');\n",
+ " this._root_extra_style(this.root);\n",
+ "\n",
+ " parent_element.appendChild(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 (fig.ratio !== 1) {\n",
+ " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.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 = document.createElement('div');\n",
+ " titlebar.classList =\n",
+ " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
+ " var titletext = document.createElement('div');\n",
+ " titletext.classList = 'ui-dialog-title';\n",
+ " titletext.setAttribute(\n",
+ " 'style',\n",
+ " 'width: 100%; text-align: center; padding: 3px;'\n",
+ " );\n",
+ " titlebar.appendChild(titletext);\n",
+ " this.root.appendChild(titlebar);\n",
+ " this.header = titletext;\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
+ "\n",
+ "mpl.figure.prototype._init_canvas = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
+ " canvas_div.setAttribute(\n",
+ " 'style',\n",
+ " 'border: 1px solid #ddd;' +\n",
+ " 'box-sizing: content-box;' +\n",
+ " 'clear: both;' +\n",
+ " 'min-height: 1px;' +\n",
+ " 'min-width: 1px;' +\n",
+ " 'outline: 0;' +\n",
+ " 'overflow: hidden;' +\n",
+ " 'position: relative;' +\n",
+ " 'resize: both;'\n",
+ " );\n",
+ "\n",
+ " function on_keyboard_event_closure(name) {\n",
+ " return function (event) {\n",
+ " return fig.key_event(event, name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " canvas_div.addEventListener(\n",
+ " 'keydown',\n",
+ " on_keyboard_event_closure('key_press')\n",
+ " );\n",
+ " canvas_div.addEventListener(\n",
+ " 'keyup',\n",
+ " on_keyboard_event_closure('key_release')\n",
+ " );\n",
+ "\n",
+ " this._canvas_extra_style(canvas_div);\n",
+ " this.root.appendChild(canvas_div);\n",
+ "\n",
+ " var canvas = (this.canvas = document.createElement('canvas'));\n",
+ " canvas.classList.add('mpl-canvas');\n",
+ " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
+ "\n",
+ " this.context = canvas.getContext('2d');\n",
+ "\n",
+ " var backingStore =\n",
+ " this.context.backingStorePixelRatio ||\n",
+ " this.context.webkitBackingStorePixelRatio ||\n",
+ " this.context.mozBackingStorePixelRatio ||\n",
+ " this.context.msBackingStorePixelRatio ||\n",
+ " this.context.oBackingStorePixelRatio ||\n",
+ " this.context.backingStorePixelRatio ||\n",
+ " 1;\n",
+ "\n",
+ " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
+ " 'canvas'\n",
+ " ));\n",
+ " rubberband_canvas.setAttribute(\n",
+ " 'style',\n",
+ " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
+ " );\n",
+ "\n",
+ " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
+ " if (this.ResizeObserver === undefined) {\n",
+ " if (window.ResizeObserver !== undefined) {\n",
+ " this.ResizeObserver = window.ResizeObserver;\n",
+ " } else {\n",
+ " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
+ " this.ResizeObserver = obs.ResizeObserver;\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
+ " var nentries = entries.length;\n",
+ " for (var i = 0; i < nentries; i++) {\n",
+ " var entry = entries[i];\n",
+ " var width, height;\n",
+ " if (entry.contentBoxSize) {\n",
+ " if (entry.contentBoxSize instanceof Array) {\n",
+ " // Chrome 84 implements new version of spec.\n",
+ " width = entry.contentBoxSize[0].inlineSize;\n",
+ " height = entry.contentBoxSize[0].blockSize;\n",
+ " } else {\n",
+ " // Firefox implements old version of spec.\n",
+ " width = entry.contentBoxSize.inlineSize;\n",
+ " height = entry.contentBoxSize.blockSize;\n",
+ " }\n",
+ " } else {\n",
+ " // Chrome <84 implements even older version of spec.\n",
+ " width = entry.contentRect.width;\n",
+ " height = entry.contentRect.height;\n",
+ " }\n",
+ "\n",
+ " // Keep the size of the canvas and rubber band canvas in sync with\n",
+ " // the canvas container.\n",
+ " if (entry.devicePixelContentBoxSize) {\n",
+ " // Chrome 84 implements new version of spec.\n",
+ " canvas.setAttribute(\n",
+ " 'width',\n",
+ " entry.devicePixelContentBoxSize[0].inlineSize\n",
+ " );\n",
+ " canvas.setAttribute(\n",
+ " 'height',\n",
+ " entry.devicePixelContentBoxSize[0].blockSize\n",
+ " );\n",
+ " } else {\n",
+ " canvas.setAttribute('width', width * fig.ratio);\n",
+ " canvas.setAttribute('height', height * fig.ratio);\n",
+ " }\n",
+ " canvas.setAttribute(\n",
+ " 'style',\n",
+ " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
+ " );\n",
+ "\n",
+ " rubberband_canvas.setAttribute('width', width);\n",
+ " rubberband_canvas.setAttribute('height', height);\n",
+ "\n",
+ " // And update the size in Python. We ignore the initial 0/0 size\n",
+ " // that occurs as the element is placed into the DOM, which should\n",
+ " // otherwise not happen due to the minimum size styling.\n",
+ " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
+ " fig.request_resize(width, height);\n",
+ " }\n",
+ " }\n",
+ " });\n",
+ " this.resizeObserverInstance.observe(canvas_div);\n",
+ "\n",
+ " function on_mouse_event_closure(name) {\n",
+ " return function (event) {\n",
+ " return fig.mouse_event(event, name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mousedown',\n",
+ " on_mouse_event_closure('button_press')\n",
+ " );\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseup',\n",
+ " on_mouse_event_closure('button_release')\n",
+ " );\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mousemove',\n",
+ " on_mouse_event_closure('motion_notify')\n",
+ " );\n",
+ "\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseenter',\n",
+ " on_mouse_event_closure('figure_enter')\n",
+ " );\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseleave',\n",
+ " on_mouse_event_closure('figure_leave')\n",
+ " );\n",
+ "\n",
+ " canvas_div.addEventListener('wheel', function (event) {\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " on_mouse_event_closure('scroll')(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.appendChild(canvas);\n",
+ " canvas_div.appendChild(rubberband_canvas);\n",
+ "\n",
+ " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
+ " this.rubberband_context.strokeStyle = '#000000';\n",
+ "\n",
+ " this._resize_canvas = function (width, height, forward) {\n",
+ " if (forward) {\n",
+ " canvas_div.style.width = width + 'px';\n",
+ " canvas_div.style.height = height + 'px';\n",
+ " }\n",
+ " };\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
+ " event.preventDefault();\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 toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'mpl-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'mpl-button-group';\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'mpl-button-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " var button = (fig.buttons[name] = document.createElement('button'));\n",
+ " button.classList = 'mpl-widget';\n",
+ " button.setAttribute('role', 'button');\n",
+ " button.setAttribute('aria-disabled', 'false');\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ "\n",
+ " var icon_img = document.createElement('img');\n",
+ " icon_img.src = '_images/' + image + '.png';\n",
+ " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
+ " icon_img.alt = tooltip;\n",
+ " button.appendChild(icon_img);\n",
+ "\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker = document.createElement('select');\n",
+ " fmt_picker.classList = 'mpl-widget';\n",
+ " toolbar.appendChild(fmt_picker);\n",
+ " this.format_dropdown = fmt_picker;\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = document.createElement('option');\n",
+ " option.selected = fmt === mpl.default_extension;\n",
+ " option.innerHTML = fmt;\n",
+ " fmt_picker.appendChild(option);\n",
+ " }\n",
+ "\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\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",
+ "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",
+ "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], msg['forward']);\n",
+ " fig.send_message('refresh', {});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
+ " var x0 = msg['x0'] / fig.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
+ " var x1 = msg['x1'] / fig.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / fig.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,\n",
+ " 0,\n",
+ " fig.canvas.width / fig.ratio,\n",
+ " fig.canvas.height / fig.ratio\n",
+ " );\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",
+ " 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.handle_history_buttons = function (fig, msg) {\n",
+ " for (var key in msg) {\n",
+ " if (!(key in fig.buttons)) {\n",
+ " continue;\n",
+ " }\n",
+ " fig.buttons[key].disabled = !msg[key];\n",
+ " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
+ " if (msg['mode'] === 'PAN') {\n",
+ " fig.buttons['Pan'].classList.add('active');\n",
+ " fig.buttons['Zoom'].classList.remove('active');\n",
+ " } else if (msg['mode'] === 'ZOOM') {\n",
+ " fig.buttons['Pan'].classList.remove('active');\n",
+ " fig.buttons['Zoom'].classList.add('active');\n",
+ " } else {\n",
+ " fig.buttons['Pan'].classList.remove('active');\n",
+ " fig.buttons['Zoom'].classList.remove('active');\n",
+ " }\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",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data\n",
+ " );\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " } else if (\n",
+ " typeof evt.data === 'string' &&\n",
+ " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
+ " ) {\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(\n",
+ " \"No handler for the '\" + msg_type + \"' message type: \",\n",
+ " msg\n",
+ " );\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(\n",
+ " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
+ " e,\n",
+ " e.stack,\n",
+ " msg\n",
+ " );\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",
+ " }\n",
+ " if (e.target) {\n",
+ " targ = e.target;\n",
+ " } else if (e.srcElement) {\n",
+ " targ = e.srcElement;\n",
+ " }\n",
+ " if (targ.nodeType === 3) {\n",
+ " // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ " }\n",
+ "\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " var boundingRect = targ.getBoundingClientRect();\n",
+ " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
+ " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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",
+ " }\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",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * this.ratio;\n",
+ " var y = canvas_pos.y * this.ratio;\n",
+ "\n",
+ " this.send_message(name, {\n",
+ " x: x,\n",
+ " y: y,\n",
+ " button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event),\n",
+ " });\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",
+ " // Prevent repeat events\n",
+ " if (name === 'key_press') {\n",
+ " if (event.which === this._key) {\n",
+ " return;\n",
+ " } else {\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " }\n",
+ " if (name === 'key_release') {\n",
+ " this._key = null;\n",
+ " }\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which !== 17) {\n",
+ " value += 'ctrl+';\n",
+ " }\n",
+ " if (event.altKey && event.which !== 18) {\n",
+ " value += 'alt+';\n",
+ " }\n",
+ " if (event.shiftKey && event.which !== 16) {\n",
+ " value += 'shift+';\n",
+ " }\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, 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",
+ "\n",
+ "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
+ "// prettier-ignore\n",
+ "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n",
+ "\n",
+ "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 = document.getElementById(id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm);\n",
+ "\n",
+ " function ondownload(figure, _format) {\n",
+ " window.open(figure.canvas.toDataURL());\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error('Failed to find cell for figure', id, fig);\n",
+ " return;\n",
+ " }\n",
+ " fig.cell_info[0].output_area.element.on(\n",
+ " 'cleared',\n",
+ " { fig: fig },\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
+ " var width = fig.canvas.width / fig.ratio;\n",
+ " fig.cell_info[0].output_area.element.off(\n",
+ " 'cleared',\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ " fig.resizeObserverInstance.unobserve(fig.canvas_div);\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.innerHTML =\n",
+ " '';\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 / this.ratio;\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] =\n",
+ " '';\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 () {\n",
+ " fig.push_to_output();\n",
+ " }, 1000);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'btn-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " var button;\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " button = fig.buttons[name] = document.createElement('button');\n",
+ " button.classList = 'btn btn-default';\n",
+ " button.href = '#';\n",
+ " button.title = name;\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message pull-right';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = document.createElement('div');\n",
+ " buttongrp.classList = 'btn-group inline pull-right';\n",
+ " button = document.createElement('button');\n",
+ " button.classList = 'btn btn-mini btn-primary';\n",
+ " button.href = '#';\n",
+ " button.title = 'Stop Interaction';\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', function (_evt) {\n",
+ " fig.handle_close(fig, {});\n",
+ " });\n",
+ " button.addEventListener(\n",
+ " 'mouseover',\n",
+ " on_mouseover_closure('Stop Interaction')\n",
+ " );\n",
+ " buttongrp.appendChild(button);\n",
+ " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
+ " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
+ " var fig = event.data.fig;\n",
+ " if (event.target !== this) {\n",
+ " // Ignore bubbled events from children.\n",
+ " return;\n",
+ " }\n",
+ " fig.close_ws(fig, {});\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (el) {\n",
+ " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
+ " // this is important to make the div 'focusable\n",
+ " el.setAttribute('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",
+ " } else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\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",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which === 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
+ " fig.ondownload(fig, null);\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(\n",
+ " 'matplotlib',\n",
+ " mpl.mpl_figure_comm\n",
+ " );\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig=plt.figure(figsize=(9,6))\n",
+ "fig.subplots_adjust(bottom=0.05, left=0.1, top = 0.99, right=0.9,wspace=0.0,hspace=0.15)\n",
+ "fig.suptitle('')\n",
+ "\n",
+ "\n",
+ "\n",
+ "_c=['xkcd:black','xkcd:red','xkcd:blue']\n",
+ "sub = fig.add_subplot(311)\n",
+ "\n",
+ "sub.plot(t,y1,c=_c[0],alpha=0.5,linestyle='-',linewidth=3,label=r'$y_{1}(t)$')\n",
+ "sub.plot(t,y2,c=_c[1],alpha=0.5,linestyle='-',linewidth=3,label=r'$y_{2}(t)$')\n",
+ "sub.plot(t,y3,c=_c[2],alpha=0.5,linestyle='-',linewidth=3,label=r'$y_{3}(t)$')\n",
+ "\n",
+ "\n",
+ "sub.plot(t_py,y_py[:,0],c=_c[0],alpha=1,linestyle=':',linewidth=2,label=r'$y_{1}(t)$ scipy')\n",
+ "sub.plot(t_py,y_py[:,1],c=_c[1],alpha=1,linestyle=':',linewidth=2,label=r'$y_{2}(t)$ scipy')\n",
+ "sub.plot(t_py,y_py[:,2],c=_c[2],alpha=1,linestyle=':',linewidth=2,label=r'$y_{3}(t)$ scipy')\n",
+ "\n",
+ "# sub.plot(t,sol_ode[:,0],c=_c[0],alpha=1,linestyle='--',linewidth=2,label=r'$y_{1}(t)$ scipy-odeint')\n",
+ "# sub.plot(t,sol_ode[:,1],c=_c[1],alpha=1,linestyle='--',linewidth=2,label=r'$y_{2}(t)$ scipy-odeint')\n",
+ "# sub.plot(t,sol_ode[:,2],c=_c[2],alpha=1,linestyle='--',linewidth=2,label=r'$y_{3}(t)$ scipy-odeint')\n",
+ "\n",
+ "\n",
+ "sub.legend(framealpha=0,ncol=2,loc='upper right',bbox_to_anchor=(1,.9))\n",
+ "# sub.set_xscale('log')\n",
+ "# sub.set_yscale('log')\n",
+ "\n",
+ "sub.set_ylabel('y') \n",
+ "# sub.set_xlim(0,1) \n",
+ "\n",
+ "\n",
+ "\n",
+ "sub = fig.add_subplot(312) \n",
+ "sub.hist(t,color=_c[0],label=r'mine',bins=25 )\n",
+ "# sub.plot(t,hist)\n",
+ "# sub.set_xscale('log')\n",
+ "\n",
+ "sub.set_ylabel('No. steps')\n",
+ "\n",
+ "\n",
+ "sub.set_ylabel(r' $\\dfrac{\\Delta y}{\\rm scale} \\lesssim 1$ ')\n",
+ "sub.set_xlabel('') \n",
+ "\n",
+ "\n",
+ "sub = fig.add_subplot(313) \n",
+ "sub.plot(t,np.abs(err1/y1),c=_c[0],alpha=1,linestyle='--',linewidth=3,label=r'$y_{1}(t)$')\n",
+ "sub.plot(t,np.abs(err2/y2),c=_c[1],alpha=1,linestyle='--',linewidth=3,label=r'$y_{2}(t)$')\n",
+ "sub.plot(t,np.abs(err3/y3),c=_c[2],alpha=1,linestyle='--',linewidth=3,label=r'$y_{3}(t)$')\n",
+ "sub.legend(framealpha=0,ncol=2,loc='upper right',bbox_to_anchor=(1,.9))\n",
+ "\n",
+ "sub.set_yscale('log')\n",
+ "# sub.set_xscale('log')\n",
+ "\n",
+ "sub.set_ylabel(r' $\\dfrac{\\Delta y}{ y} $ ')\n",
+ "sub.set_xlabel('t') \n",
+ "\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "/* global mpl */\n",
+ "window.mpl = {};\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(\n",
+ " '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",
+ "\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 = document.createElement('div');\n",
+ " this.root.setAttribute('style', 'display: inline-block');\n",
+ " this._root_extra_style(this.root);\n",
+ "\n",
+ " parent_element.appendChild(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 (fig.ratio !== 1) {\n",
+ " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.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 = document.createElement('div');\n",
+ " titlebar.classList =\n",
+ " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
+ " var titletext = document.createElement('div');\n",
+ " titletext.classList = 'ui-dialog-title';\n",
+ " titletext.setAttribute(\n",
+ " 'style',\n",
+ " 'width: 100%; text-align: center; padding: 3px;'\n",
+ " );\n",
+ " titlebar.appendChild(titletext);\n",
+ " this.root.appendChild(titlebar);\n",
+ " this.header = titletext;\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
+ "\n",
+ "mpl.figure.prototype._init_canvas = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
+ " canvas_div.setAttribute(\n",
+ " 'style',\n",
+ " 'border: 1px solid #ddd;' +\n",
+ " 'box-sizing: content-box;' +\n",
+ " 'clear: both;' +\n",
+ " 'min-height: 1px;' +\n",
+ " 'min-width: 1px;' +\n",
+ " 'outline: 0;' +\n",
+ " 'overflow: hidden;' +\n",
+ " 'position: relative;' +\n",
+ " 'resize: both;'\n",
+ " );\n",
+ "\n",
+ " function on_keyboard_event_closure(name) {\n",
+ " return function (event) {\n",
+ " return fig.key_event(event, name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " canvas_div.addEventListener(\n",
+ " 'keydown',\n",
+ " on_keyboard_event_closure('key_press')\n",
+ " );\n",
+ " canvas_div.addEventListener(\n",
+ " 'keyup',\n",
+ " on_keyboard_event_closure('key_release')\n",
+ " );\n",
+ "\n",
+ " this._canvas_extra_style(canvas_div);\n",
+ " this.root.appendChild(canvas_div);\n",
+ "\n",
+ " var canvas = (this.canvas = document.createElement('canvas'));\n",
+ " canvas.classList.add('mpl-canvas');\n",
+ " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
+ "\n",
+ " this.context = canvas.getContext('2d');\n",
+ "\n",
+ " var backingStore =\n",
+ " this.context.backingStorePixelRatio ||\n",
+ " this.context.webkitBackingStorePixelRatio ||\n",
+ " this.context.mozBackingStorePixelRatio ||\n",
+ " this.context.msBackingStorePixelRatio ||\n",
+ " this.context.oBackingStorePixelRatio ||\n",
+ " this.context.backingStorePixelRatio ||\n",
+ " 1;\n",
+ "\n",
+ " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
+ " 'canvas'\n",
+ " ));\n",
+ " rubberband_canvas.setAttribute(\n",
+ " 'style',\n",
+ " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
+ " );\n",
+ "\n",
+ " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
+ " if (this.ResizeObserver === undefined) {\n",
+ " if (window.ResizeObserver !== undefined) {\n",
+ " this.ResizeObserver = window.ResizeObserver;\n",
+ " } else {\n",
+ " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
+ " this.ResizeObserver = obs.ResizeObserver;\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
+ " var nentries = entries.length;\n",
+ " for (var i = 0; i < nentries; i++) {\n",
+ " var entry = entries[i];\n",
+ " var width, height;\n",
+ " if (entry.contentBoxSize) {\n",
+ " if (entry.contentBoxSize instanceof Array) {\n",
+ " // Chrome 84 implements new version of spec.\n",
+ " width = entry.contentBoxSize[0].inlineSize;\n",
+ " height = entry.contentBoxSize[0].blockSize;\n",
+ " } else {\n",
+ " // Firefox implements old version of spec.\n",
+ " width = entry.contentBoxSize.inlineSize;\n",
+ " height = entry.contentBoxSize.blockSize;\n",
+ " }\n",
+ " } else {\n",
+ " // Chrome <84 implements even older version of spec.\n",
+ " width = entry.contentRect.width;\n",
+ " height = entry.contentRect.height;\n",
+ " }\n",
+ "\n",
+ " // Keep the size of the canvas and rubber band canvas in sync with\n",
+ " // the canvas container.\n",
+ " if (entry.devicePixelContentBoxSize) {\n",
+ " // Chrome 84 implements new version of spec.\n",
+ " canvas.setAttribute(\n",
+ " 'width',\n",
+ " entry.devicePixelContentBoxSize[0].inlineSize\n",
+ " );\n",
+ " canvas.setAttribute(\n",
+ " 'height',\n",
+ " entry.devicePixelContentBoxSize[0].blockSize\n",
+ " );\n",
+ " } else {\n",
+ " canvas.setAttribute('width', width * fig.ratio);\n",
+ " canvas.setAttribute('height', height * fig.ratio);\n",
+ " }\n",
+ " canvas.setAttribute(\n",
+ " 'style',\n",
+ " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
+ " );\n",
+ "\n",
+ " rubberband_canvas.setAttribute('width', width);\n",
+ " rubberband_canvas.setAttribute('height', height);\n",
+ "\n",
+ " // And update the size in Python. We ignore the initial 0/0 size\n",
+ " // that occurs as the element is placed into the DOM, which should\n",
+ " // otherwise not happen due to the minimum size styling.\n",
+ " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
+ " fig.request_resize(width, height);\n",
+ " }\n",
+ " }\n",
+ " });\n",
+ " this.resizeObserverInstance.observe(canvas_div);\n",
+ "\n",
+ " function on_mouse_event_closure(name) {\n",
+ " return function (event) {\n",
+ " return fig.mouse_event(event, name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mousedown',\n",
+ " on_mouse_event_closure('button_press')\n",
+ " );\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseup',\n",
+ " on_mouse_event_closure('button_release')\n",
+ " );\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mousemove',\n",
+ " on_mouse_event_closure('motion_notify')\n",
+ " );\n",
+ "\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseenter',\n",
+ " on_mouse_event_closure('figure_enter')\n",
+ " );\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseleave',\n",
+ " on_mouse_event_closure('figure_leave')\n",
+ " );\n",
+ "\n",
+ " canvas_div.addEventListener('wheel', function (event) {\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " on_mouse_event_closure('scroll')(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.appendChild(canvas);\n",
+ " canvas_div.appendChild(rubberband_canvas);\n",
+ "\n",
+ " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
+ " this.rubberband_context.strokeStyle = '#000000';\n",
+ "\n",
+ " this._resize_canvas = function (width, height, forward) {\n",
+ " if (forward) {\n",
+ " canvas_div.style.width = width + 'px';\n",
+ " canvas_div.style.height = height + 'px';\n",
+ " }\n",
+ " };\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
+ " event.preventDefault();\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 toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'mpl-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'mpl-button-group';\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'mpl-button-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " var button = (fig.buttons[name] = document.createElement('button'));\n",
+ " button.classList = 'mpl-widget';\n",
+ " button.setAttribute('role', 'button');\n",
+ " button.setAttribute('aria-disabled', 'false');\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ "\n",
+ " var icon_img = document.createElement('img');\n",
+ " icon_img.src = '_images/' + image + '.png';\n",
+ " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
+ " icon_img.alt = tooltip;\n",
+ " button.appendChild(icon_img);\n",
+ "\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker = document.createElement('select');\n",
+ " fmt_picker.classList = 'mpl-widget';\n",
+ " toolbar.appendChild(fmt_picker);\n",
+ " this.format_dropdown = fmt_picker;\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = document.createElement('option');\n",
+ " option.selected = fmt === mpl.default_extension;\n",
+ " option.innerHTML = fmt;\n",
+ " fmt_picker.appendChild(option);\n",
+ " }\n",
+ "\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\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",
+ "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",
+ "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], msg['forward']);\n",
+ " fig.send_message('refresh', {});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
+ " var x0 = msg['x0'] / fig.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
+ " var x1 = msg['x1'] / fig.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / fig.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,\n",
+ " 0,\n",
+ " fig.canvas.width / fig.ratio,\n",
+ " fig.canvas.height / fig.ratio\n",
+ " );\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",
+ " 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.handle_history_buttons = function (fig, msg) {\n",
+ " for (var key in msg) {\n",
+ " if (!(key in fig.buttons)) {\n",
+ " continue;\n",
+ " }\n",
+ " fig.buttons[key].disabled = !msg[key];\n",
+ " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
+ " if (msg['mode'] === 'PAN') {\n",
+ " fig.buttons['Pan'].classList.add('active');\n",
+ " fig.buttons['Zoom'].classList.remove('active');\n",
+ " } else if (msg['mode'] === 'ZOOM') {\n",
+ " fig.buttons['Pan'].classList.remove('active');\n",
+ " fig.buttons['Zoom'].classList.add('active');\n",
+ " } else {\n",
+ " fig.buttons['Pan'].classList.remove('active');\n",
+ " fig.buttons['Zoom'].classList.remove('active');\n",
+ " }\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",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data\n",
+ " );\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " } else if (\n",
+ " typeof evt.data === 'string' &&\n",
+ " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
+ " ) {\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(\n",
+ " \"No handler for the '\" + msg_type + \"' message type: \",\n",
+ " msg\n",
+ " );\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(\n",
+ " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
+ " e,\n",
+ " e.stack,\n",
+ " msg\n",
+ " );\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",
+ " }\n",
+ " if (e.target) {\n",
+ " targ = e.target;\n",
+ " } else if (e.srcElement) {\n",
+ " targ = e.srcElement;\n",
+ " }\n",
+ " if (targ.nodeType === 3) {\n",
+ " // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ " }\n",
+ "\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " var boundingRect = targ.getBoundingClientRect();\n",
+ " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
+ " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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",
+ " }\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",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * this.ratio;\n",
+ " var y = canvas_pos.y * this.ratio;\n",
+ "\n",
+ " this.send_message(name, {\n",
+ " x: x,\n",
+ " y: y,\n",
+ " button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event),\n",
+ " });\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",
+ " // Prevent repeat events\n",
+ " if (name === 'key_press') {\n",
+ " if (event.which === this._key) {\n",
+ " return;\n",
+ " } else {\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " }\n",
+ " if (name === 'key_release') {\n",
+ " this._key = null;\n",
+ " }\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which !== 17) {\n",
+ " value += 'ctrl+';\n",
+ " }\n",
+ " if (event.altKey && event.which !== 18) {\n",
+ " value += 'alt+';\n",
+ " }\n",
+ " if (event.shiftKey && event.which !== 16) {\n",
+ " value += 'shift+';\n",
+ " }\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, 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",
+ "\n",
+ "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
+ "// prettier-ignore\n",
+ "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n",
+ "\n",
+ "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 = document.getElementById(id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm);\n",
+ "\n",
+ " function ondownload(figure, _format) {\n",
+ " window.open(figure.canvas.toDataURL());\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n",
+ " fig.cell_info = mpl.find_output_cell(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error('Failed to find cell for figure', id, fig);\n",
+ " return;\n",
+ " }\n",
+ " fig.cell_info[0].output_area.element.on(\n",
+ " 'cleared',\n",
+ " { fig: fig },\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
+ " var width = fig.canvas.width / fig.ratio;\n",
+ " fig.cell_info[0].output_area.element.off(\n",
+ " 'cleared',\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ " fig.resizeObserverInstance.unobserve(fig.canvas_div);\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.innerHTML =\n",
+ " '';\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 / this.ratio;\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] =\n",
+ " '';\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 () {\n",
+ " fig.push_to_output();\n",
+ " }, 1000);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'btn-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " var button;\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " button = fig.buttons[name] = document.createElement('button');\n",
+ " button.classList = 'btn btn-default';\n",
+ " button.href = '#';\n",
+ " button.title = name;\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message pull-right';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = document.createElement('div');\n",
+ " buttongrp.classList = 'btn-group inline pull-right';\n",
+ " button = document.createElement('button');\n",
+ " button.classList = 'btn btn-mini btn-primary';\n",
+ " button.href = '#';\n",
+ " button.title = 'Stop Interaction';\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', function (_evt) {\n",
+ " fig.handle_close(fig, {});\n",
+ " });\n",
+ " button.addEventListener(\n",
+ " 'mouseover',\n",
+ " on_mouseover_closure('Stop Interaction')\n",
+ " );\n",
+ " buttongrp.appendChild(button);\n",
+ " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
+ " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
+ " var fig = event.data.fig;\n",
+ " if (event.target !== this) {\n",
+ " // Ignore bubbled events from children.\n",
+ " return;\n",
+ " }\n",
+ " fig.close_ws(fig, {});\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (el) {\n",
+ " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
+ " // this is important to make the div 'focusable\n",
+ " el.setAttribute('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",
+ " } else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\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",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which === 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
+ " fig.ondownload(fig, null);\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(\n",
+ " 'matplotlib',\n",
+ " mpl.mpl_figure_comm\n",
+ " );\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig=plt.figure(figsize=(8,4))\n",
+ "fig.subplots_adjust(bottom=0.15, left=0.1, top = 0.99, right=0.9,wspace=0.0,hspace=0.2)\n",
+ "fig.suptitle('')\n",
+ "\n",
+ "\n",
+ "\n",
+ "_c=['xkcd:black','xkcd:red','xkcd:blue']\n",
+ "sub = fig.add_subplot(111)\n",
+ "\n",
+ "sub.hist(t,color=_c[0],label=r'mine',bins=int(t[-1]*5))\n",
+ "sub.hist(t_py,color=_c[2],label=r'scipy',alpha=0.5,bins=int(t[-1]*5))\n",
+ "\n",
+ "# check also this\n",
+ "# sub.plot(t,hist,label=r'mine')\n",
+ "# sub.hist(t_py,label=r'scipy',alpha=0.5,bins=N)\n",
+ "\n",
+ "\n",
+ "\n",
+ "sub.set_ylabel('No. steps')\n",
+ "\n",
+ "\n",
+ "sub.legend(framealpha=0,ncol=2,loc='upper right',bbox_to_anchor=(1,.9))\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1718"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(t)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2140"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(t_py)"
+ ]
+ },
+ {
+ "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.9.1"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/src/NaBBODES/RKF/Example.cpp b/src/NaBBODES/RKF/Example.cpp
new file mode 100644
index 0000000..003c652
--- /dev/null
+++ b/src/NaBBODES/RKF/Example.cpp
@@ -0,0 +1,81 @@
+// This is how you run RK.
+#include
+#include
+#include
+#include"RKF.hpp"
+#include"METHOD.hpp"
+
+
+#ifndef LONG
+#define LONG
+#endif
+
+
+#define LD LONG double
+
+
+#ifndef METHOD
+#define METHOD RKF45
+#endif
+
+
+
+#define initial_step_size 1e-2
+#define minimum_step_size 1e-5
+#define maximum_step_size 1e1
+#define maximum_No_steps 1000000
+#define absolute_tolerance 1e-9
+#define relative_tolerance 1e-9
+#define beta 0.95
+#define fac_max 1.1
+#define fac_min 0.8
+
+
+// this is how the diffeq should look like
+#define n_eqs 1 //number of equations
+using Array = std::array;//define an array type of length n_eqs
+//-------------------------------------------------------------------------//
+
+using std::pow;
+
+/*std::function supports any callable object, so we cna simply use this without overloading
+operator=, or defining copy constructor.*/
+class diffeq{
+ public:
+ LD c;
+ diffeq(double c):c(c){};
+
+ void operator()(Array &lhs, Array &y, LD t){
+ lhs[0]=t*c;
+ }
+
+};
+
+using SOLVER = RKF,LD>;
+
+int main(int argc, const char** argv) {
+ Array y0={0};
+
+ diffeq dydt(2);
+
+ SOLVER System(dydt,y0,1e1,
+ initial_step_size, minimum_step_size, maximum_step_size,
+ maximum_No_steps, absolute_tolerance, relative_tolerance, beta, fac_max, fac_min);
+
+ System.solve();
+ // return 0;
+
+ int step=0;
+ for (auto _t: System.time){
+ printf("%e ",(double)_t);
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e ", (double)System.solution[eq][step]);}
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e " ,(double)System.error[eq][step]);}
+ printf("\n");
+ step++;
+ }
+
+
+
+
+ return 0;
+ }
\ No newline at end of file
diff --git a/src/NaBBODES/RKF/METHOD.hpp b/src/NaBBODES/RKF/METHOD.hpp
new file mode 100644
index 0000000..87771a6
--- /dev/null
+++ b/src/NaBBODES/RKF/METHOD.hpp
@@ -0,0 +1,71 @@
+#ifndef RKF_METHOD
+#define RKF_METHOD
+#include
+
+template
+struct DormandPrince{
+ static constexpr unsigned int s=7;
+ static constexpr unsigned int p=4;
+
+ using arr=std::array;
+ using arr2=std::array;
+
+ static constexpr arr c={0,1/5.,3/10.,4/5.,8/9.,1.,1.};
+ static constexpr arr b={5179/57600.,0,7571/16695.,393/640.,-92097/339200.,187/2100.,1/40.};
+ static constexpr arr bstar={ 35/384.,0.,500/1113.,125/192.,-2187/6784.,11/84.,0 };
+ static constexpr arr2 a={
+ arr{0,0,0,0,0,0,0},
+ arr{1/5.,0,0,0,0,0,0},
+ arr{3/40.,9/40.,0,0,0,0,0},
+ arr{44/45.,-56/15.,32/9.,0,0,0,0},
+ arr{19372/6561.,-25360/2187.,64448/6561.,-212/729.,0,0,0},
+ arr{9017/3168.,-355/33.,46732/5247.,49/176.,-5103/18656.,0,0},
+ arr{35/384.,0,500/1113.,125/192.,-2187/6784.,11/84.,0}
+
+ };
+};
+
+template
+struct CashKarp{
+ static constexpr unsigned int s=6;
+ static constexpr unsigned int p=4;
+
+ using arr=std::array;
+ using arr2=std::array;
+
+ static constexpr arr c={0,1/5.,3/10.,3/5.,1.,7/8.};
+ static constexpr arr b={37/378.,0,250/621.,125/594.,0,512/1771.};
+ static constexpr arr bstar={2825/27648.,0.,18575/48384.,13525/55296,277/14336.,0.25};
+ static constexpr arr2 a={
+ arr{0,0,0,0,0,0},
+ arr{0.2,0,0,0,0,0},
+ arr{3/40.,9/40.,0,0,0,0},
+ arr{0.3,-0.9,6/5.,0,0,0},
+ arr{-11/54.,2.5,-70/27,35/27.,0,0},
+ arr{1631/55296.,175/512.,575/13824.,44275/110592.,253/4096.,0}
+ };
+};
+
+
+
+template
+struct RKF45{
+ static constexpr unsigned int s=6;
+ static constexpr unsigned int p=4;
+
+ using arr=std::array;
+ using arr2=std::array;
+
+ static constexpr arr c={0,1/4.,3/8.,12/13.,1.,0.5};
+ static constexpr arr b={16/135.,0,6656/12825.,28561/56430.,-9/50.,2/55.};
+ static constexpr arr bstar={25/216.,0.,1408/2565.,2197/4104,-0.2,0};
+ static constexpr arr2 a={
+ arr{0,0,0,0,0,0},
+ arr{0.25,0,0,0,0,0},
+ arr{3/32.,9/32.,0,0,0,0},
+ arr{1932/2197.,-7200/2197.,7296/2197.,0,0,0},
+ arr{439/216.,-8.,3680/513.,-845/4104.,0,0},
+ arr{-8/27.,2.,-3544/2565.,1859/4104.,-11/40.,0}
+ };
+};
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/RKF/RKF.cpp b/src/NaBBODES/RKF/RKF.cpp
new file mode 100644
index 0000000..d6f7307
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF.cpp
@@ -0,0 +1,83 @@
+// This is how you run RK.
+#include
+#include
+#include
+#include"RKF.hpp"
+#include"METHOD.hpp"
+
+
+#ifndef LONG
+#define LONG
+#endif
+
+
+#define LD LONG double
+
+
+#ifndef METHOD
+#define METHOD RKF45
+#endif
+
+
+
+#define initial_step_size 1e-2
+#define minimum_step_size 1e-8
+#define maximum_step_size 1e2
+#define maximum_No_steps 1000000
+#define absolute_tolerance 1e-9
+#define relative_tolerance 1e-9
+#define beta 0.8
+#define fac_max 1.5
+#define fac_min 0.5
+
+
+// this is how the diffeq should look like
+#define n_eqs 3 //number of equations
+using Array = std::array;//define an array type of length n_eqs
+//-------------------------------------------------------------------------//
+
+using std::pow;
+
+// you can use a function, but with a class you can also hold data that can be useful.
+class diffeq{
+ public:
+ diffeq()=default;
+ ~diffeq()=default;
+
+ void operator()(Array &lhs, Array &y, LD t){
+ lhs[0]=-20*y[0]*pow(t,2) ;
+ lhs[1]=5*y[0]*pow(t,2)+2*(-pow( y[1],2 )+pow( y[2],2 ) )*pow(t,1);
+ lhs[2]=15*y[0]*pow(t,2)+2*(pow( y[1],2 )-pow( y[2],2 ) )*pow(t,1);
+ }
+
+};
+
+
+using SOLVER = RKF,LD>;
+
+int main(int argc, const char** argv) {
+ Array y0 = {8,12,4};
+
+ diffeq dydt;
+
+ SOLVER System(dydt,y0,1e1,
+ initial_step_size, minimum_step_size, maximum_step_size,
+ maximum_No_steps, absolute_tolerance, relative_tolerance, beta, fac_max, fac_min);
+
+ System.solve();
+ // return 0;
+
+ int step=0;
+ for (auto _t: System.time){
+ printf("%e ",(double)_t);
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e ", (double)System.solution[eq][step]);}
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e " ,(double)System.error[eq][step]);}
+ printf("\n");
+ step++;
+ }
+
+
+
+
+ return 0;
+ }
\ No newline at end of file
diff --git a/src/NaBBODES/RKF/RKF.hpp b/src/NaBBODES/RKF/RKF.hpp
new file mode 100644
index 0000000..04340cd
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF.hpp
@@ -0,0 +1,13 @@
+#ifndef RKF_headers
+#define RKF_headers
+
+#include "RKF_class.hpp"
+#include "RKF_costructor.hpp"
+#include "RKF_calc_k.hpp"
+#include "RKF_sums.hpp"
+// #include "RKF_step_control-simple.hpp"
+#include "RKF_step_control-PI.hpp"
+#include "RKF_steps.hpp"
+
+
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/RKF/RKF_calc_k.hpp b/src/NaBBODES/RKF/RKF_calc_k.hpp
new file mode 100644
index 0000000..aa73c90
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_calc_k.hpp
@@ -0,0 +1,26 @@
+#ifndef RKF_calc_k
+#define RKF_calc_k
+#include "RKF_class.hpp"
+
+/*-----------------------Begin: calc_k---------------------------------*/
+template
+void RKF::calc_k(){
+ std::array yn;//thi i here to hold ynext + sum a*k
+ std::array fyn;//this is here to get dydt in each step
+
+
+ // Or for the shake of simplicity, calculae all of them in one loop (shouldn't be slower since the sum_ak for stage=0 should'n realy do anything).
+ // claculate the \vec{k}_i
+ for (unsigned int stage = 0; stage < RK_method::s; stage++){
+ // first we need the sum_{j}^{stage-1}a_{stage,j}\vec{k}_j
+ sum_ak(stage);
+ // then we need \vec{y}+sum_{j}^{stage-1}a_{stage,j}\vec{k}_j (so fill yn with this)
+ for (unsigned int eq = 0; eq < N_eqs; eq++){yn[eq]=yprev[eq]+ak[eq]*h;}
+ // then calculate f(\vec{y}+sum_{j}^{stage-1}a_{stage,j}\vec{j}, tn + c[stage]*h )
+ dydt(fyn, yn,tn+h*RK_method::c[stage] );
+ // now we can fill \vec{k}[stage]
+ for(unsigned int eq = 0; eq < N_eqs; eq++){ k[eq][stage]=fyn[eq]; }
+ }
+}
+/*-----------------------End: calc_k---------------------------------*/
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/RKF/RKF_class.hpp b/src/NaBBODES/RKF/RKF_class.hpp
new file mode 100644
index 0000000..8b9b0d4
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_class.hpp
@@ -0,0 +1,75 @@
+#ifndef RKF_class
+#define RKF_class
+
+#include
+#include
+#include
+
+//This is a general implementation of explicit embedded RK solver of
+// a system of differential equations in the interval [0,tmax].
+
+/*
+diffeq is a class of the system of equations to be solved
+N_eqs is ten number of equations to be solved
+RKF_method is the method (the DormandPrince seems to be the standard here)
+*/
+
+
+template
+class RKF{
+ private://There is no reason to make things private (if you break it it's not my fault)...
+ using diffeq=std::function &lhs, std::array &y, LD t)>;
+
+
+ LD hmin, hmax, abs_tol, rel_tol, beta, fac_max, fac_min;
+ LD h_old, delta_acc, delta_rej;//these will be initialized at the beginning of next_step
+ unsigned int max_N;
+ bool h_stop;//h_stop becomes true when suitable stepsize is found.
+ public:
+ //Inputs. The initial condition is given as a Array (the type is users choice as long as it can be called with [])
+ diffeq dydt;
+
+ LD tmax, h, tn;
+ std::array yprev;
+
+
+ std::vector time;
+ std::array, N_eqs> solution;
+ std::array, N_eqs> error;
+
+ std::array,N_eqs> k;
+ // LD k[N_eqs][RK_method::s];
+ //these are here to hold the k's, sum_i b_i*k_i, sum_i b_i^{\star}*k_i, and sum_j a_{ij}*k_j
+ std::array ak, bk, bstark;
+ // abs_delta=abs(ynext-ynext_star)
+ std::array abs_delta;
+
+ std::array ynext;//this is here to hold the prediction
+ std::array ynext_star;//this is here to hold the second prediction
+
+
+
+ RKF(diffeq dydt, const std::array& init_cond, LD tmax,
+ LD initial_step_size=1e-5, LD minimum_step_size=1e-11, LD maximum_step_size=1e-3,
+ int maximum_No_steps=1000000, LD absolute_tolerance=1e-8,LD relative_tolerance=1e-8,
+ LD beta=0.85,LD fac_max=3, LD fac_min=0.3);
+
+ ~RKF()=default;
+
+ /*-------------------it would be nice to have a way to define these sums more generaly-----------------*/
+ void next_step();
+
+ void calc_k();
+
+ void sum_ak(unsigned int stage); // calculate sum_j a_{ij}*k_j and passit to this->ak
+ void sum_bk();// calculate sum_i b_i*k_i and passit to this->bk
+ void sum_bstark();// calculate sum_i b^{\star}_i*k_i and passit to this->bk
+
+ void step_control();//adjust stepsize until error is acceptable
+
+ void solve();
+};
+
+
+
+#endif
diff --git a/src/NaBBODES/RKF/RKF_costructor.hpp b/src/NaBBODES/RKF/RKF_costructor.hpp
new file mode 100644
index 0000000..f6dce4a
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_costructor.hpp
@@ -0,0 +1,46 @@
+#ifndef RKF_constructor
+#define RKF_constructor
+#include "RKF_class.hpp"
+
+//The constructor. Remember that N has default value
+template
+RKF::RKF(diffeq dydt, const std::array& init_cond, LD tmax,
+ LD initial_step_size, LD minimum_step_size, LD maximum_step_size,int maximum_No_steps,
+ LD absolute_tolerance,LD relative_tolerance,LD beta,LD fac_max, LD fac_min){
+ // Initialize inputs
+ this->dydt=dydt;
+ this->tmax=tmax;
+ this->h=initial_step_size;
+ this->hmin=minimum_step_size;
+ this->hmax=maximum_step_size;
+ this->max_N=maximum_No_steps;
+ this->abs_tol=absolute_tolerance;
+ this->rel_tol=relative_tolerance;
+ this->beta=beta;
+ this->fac_max=fac_max;
+ this->fac_min=fac_min;
+
+ // ---------------------------------------------------------------------------------- //
+ (this->time).push_back(0);
+ //define yprev[N_eqs]. It is also good to initialize ynext.
+ for(unsigned int i = 0; i < N_eqs ;++i) {
+ this->yprev[i]=init_cond[i];
+ this->ynext[i]=init_cond[i];
+ (this->solution)[i].push_back( init_cond[i]);
+ (this->error)[i].push_back(0);
+ }
+
+ // ---------------------------------------------------------------------------------- //
+
+ // Initialize k=0 for definiteness.
+ for(unsigned int i = 0; i < N_eqs ;++i){for(unsigned int j=0; jk[i][j]=0;}}
+
+ //initialize tn, current_step, and End
+ this->tn=0;
+ //initialize delta_acc
+ delta_acc=1.;
+
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/RKF/RKF_step_control-PI.hpp b/src/NaBBODES/RKF/RKF_step_control-PI.hpp
new file mode 100644
index 0000000..e1a28eb
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_step_control-PI.hpp
@@ -0,0 +1,56 @@
+#ifndef RKF_step_control
+#define RKF_step_control
+#include "RKF_class.hpp"
+
+#define max(a,b) (a <= b) ? b : a
+
+
+/*-----------------------Begin: step_control---------------------------------*/
+
+template
+void RKF::step_control(){
+ LD Delta=0.;
+ LD _sc=0;
+ LD fac=beta;
+
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ _sc=max(std::abs( ynext[eq] ), std::abs( yprev[eq] ));
+ _sc=abs_tol+rel_tol*_sc;
+ Delta+= (abs_delta[eq]/_sc)*(abs_delta[eq]/_sc);
+
+ ;}
+ Delta=std::sqrt(1./N_eqs*Delta);
+ if(Delta==0){Delta=abs_tol*rel_tol;}
+
+ // I use the step control from
+ // https://www.sciencedirect.com/science/article/pii/S147466701751767X
+ if(Delta<=1) {
+ if(delta_rej<=1){fac*=h/h_old; }
+ fac*=std::pow(Delta, -0.65/( (LD) RK_method::p + 1.) );
+ fac*=std::pow( delta_acc/Delta, 0.3/ ( (LD) RK_method::p + 1. ) );
+ // fac*=std::pow(Deltas[current_step-1]/Delta/Delta, 1/((LD) RK_method::p+1.) ) ;
+ h_stop=true ;
+ }else{
+ fac*=std::pow( Delta , -1./( static_cast(RK_method::p+1) ));
+ }
+
+ //this is an alternative. Not very good for some reason.
+ // fac*=h/h_old*std::pow(Deltas[current_step-1]/Delta/Delta, 1/((LD) RK_method::p+1.) ) ;
+
+ if(fac> fac_max){fac = fac_max;}
+ if(fac< fac_min){fac = fac_min;}
+ h=h*fac ;
+
+ if(Delta<=1){h_stop=true;}
+ if (h>hmax ){ h=hmax; h_stop=true;}
+ if (htmax ){ h=tmax-tn; }
+}
+/*-----------------------End: step_control---------------------------------*/
+
+#undef max
+
+#endif
diff --git a/src/NaBBODES/RKF/RKF_step_control-simple.hpp b/src/NaBBODES/RKF/RKF_step_control-simple.hpp
new file mode 100644
index 0000000..f5662f0
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_step_control-simple.hpp
@@ -0,0 +1,40 @@
+#ifndef RKF_step_control
+#define RKF_step_control
+#include "RKF_class.hpp"
+
+#define max(a,b) (a <= b) ? b : a
+
+
+/*-----------------------Begin: step_control---------------------------------*/
+
+template
+void RKF::step_control(){
+ LD Delta=0.;
+ LD _sc;
+ LD fac=beta;
+
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ _sc=max(std::abs( ynext[eq] ), std::abs( yprev[eq] ));
+ _sc=abs_tol+rel_tol*_sc;
+ Delta+= (abs_delta[eq]/_sc)*(abs_delta[eq]/_sc);
+ ;}
+
+ Delta=std::sqrt(1./N_eqs*Delta);
+ if(Delta<1) { h_stop=true ; }
+
+ //step size cotrol from "Solving Ordinary Differential Equations I"
+ fac*=std::pow( Delta , -1./( static_cast(RK_method::p+1) ));
+ if(fac> fac_max){fac = fac_max;}
+ if(fac< fac_min){fac = fac_min;}
+
+ h=h*fac;
+
+ if (h>hmax ){ h=hmax; h_stop=true;}
+ if (htmax ){h=tmax-tn;}
+}
+/*-----------------------End: step_control---------------------------------*/
+
+#undef max
+
+#endif
diff --git a/src/NaBBODES/RKF/RKF_steps.hpp b/src/NaBBODES/RKF/RKF_steps.hpp
new file mode 100644
index 0000000..c4a4a70
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_steps.hpp
@@ -0,0 +1,72 @@
+#ifndef RKF_steps
+#define RKF_steps
+#include "RKF_class.hpp"
+
+
+
+/*---------------------------------------------------Begin: Get next step-------------------------------------------------------------------------------*/
+template
+void RKF::next_step(){
+ //set h_stop=false, to start looking for stepsize
+ h_stop=false;
+
+ h_old=h;//for the PI controller
+ delta_rej=delta_acc;//for the PI controller
+
+ //calculate ynext and ynext_star until h_stop=true
+ while (true){
+ // calculate \vec{k}:
+ calc_k();
+
+ // now we can calulate \vec{y}_{n+1}
+ // for this we need sum_{i}^{s}b_{i}\vec{k}_i *h. That is, call sum_bk
+ sum_bk();
+
+ // having bk, we now have \vec{y}_{n+1} \vec{y}^{\star}_{n+1}.
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ ynext[eq] = yprev[eq] + bk[eq]*h;
+ ynext_star[eq] = yprev[eq] + bstark[eq]*h;
+ // calculate the error
+ abs_delta[eq]= ynext[eq] - ynext_star[eq] ;
+ }
+
+ // call step_control to see if the error is acceptable
+ step_control();
+
+ if(h_stop){break;}
+ }
+}
+/*---------------------------------------------------End: Get next step-------------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------Begin: solve-------------------------------------------------------------------------------*/
+template
+void RKF::solve(){
+ unsigned int current_step=0;
+ while (true){
+ //increase current_step
+ current_step++;
+ // check if it's done
+ if(tn>=tmax or current_step == max_N){break;}
+ // run next step
+ next_step();
+
+ // set previous y to last one
+ for (unsigned int eq = 0; eq < N_eqs; eq++){yprev[eq]=ynext[eq];}
+ // increase time
+ tn+=h;
+
+ // store everything
+ time.push_back(tn);
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ solution[eq].push_back( ynext[eq] );
+ error[eq].push_back(ynext[eq] - ynext_star[eq]);
+ }
+ }
+}
+/*---------------------------------------------------End: solve-------------------------------------------------------------------------------*/
+
+
+
+
+#endif
diff --git a/src/NaBBODES/RKF/RKF_sums.hpp b/src/NaBBODES/RKF/RKF_sums.hpp
new file mode 100644
index 0000000..900c627
--- /dev/null
+++ b/src/NaBBODES/RKF/RKF_sums.hpp
@@ -0,0 +1,36 @@
+#ifndef RKF_sums
+#define RKF_sums
+#include "RKF_class.hpp"
+
+/*-----------------------Begin: sum_ak---------------------------------*/
+template
+void RKF::sum_ak(unsigned int stage){
+ // this function stores sum_{j}^{stage-1}a_{stage,j}\vec{k}_j in ak, so we first need to make all elements zero, and then take the sum for each component
+ for (unsigned int eq = 0; eq
+void RKF::sum_bk(){
+ // this function stores sum_{i}^{s}b_{i}\vec{k}_i in bk and sum_{i}^{s}b_{i}^{\star}\vec{k}_i in bstark
+ for (unsigned int eq = 0; eq open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element;\n",
+ " fig.cell_info = mpl.find_output_cell(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error('Failed to find cell for figure', id, fig);\n",
+ " return;\n",
+ " }\n",
+ " fig.cell_info[0].output_area.element.on(\n",
+ " 'cleared',\n",
+ " { fig: fig },\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
+ " var width = fig.canvas.width / fig.ratio;\n",
+ " fig.cell_info[0].output_area.element.off(\n",
+ " 'cleared',\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ " fig.resizeObserverInstance.unobserve(fig.canvas_div);\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.innerHTML =\n",
+ " '';\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 / this.ratio;\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] =\n",
+ " '';\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 () {\n",
+ " fig.push_to_output();\n",
+ " }, 1000);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'btn-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " var button;\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " button = fig.buttons[name] = document.createElement('button');\n",
+ " button.classList = 'btn btn-default';\n",
+ " button.href = '#';\n",
+ " button.title = name;\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message pull-right';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = document.createElement('div');\n",
+ " buttongrp.classList = 'btn-group inline pull-right';\n",
+ " button = document.createElement('button');\n",
+ " button.classList = 'btn btn-mini btn-primary';\n",
+ " button.href = '#';\n",
+ " button.title = 'Stop Interaction';\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', function (_evt) {\n",
+ " fig.handle_close(fig, {});\n",
+ " });\n",
+ " button.addEventListener(\n",
+ " 'mouseover',\n",
+ " on_mouseover_closure('Stop Interaction')\n",
+ " );\n",
+ " buttongrp.appendChild(button);\n",
+ " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
+ " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
+ " var fig = event.data.fig;\n",
+ " if (event.target !== this) {\n",
+ " // Ignore bubbled events from children.\n",
+ " return;\n",
+ " }\n",
+ " fig.close_ws(fig, {});\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (el) {\n",
+ " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
+ " // this is important to make the div 'focusable\n",
+ " el.setAttribute('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",
+ " } else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\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",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which === 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
+ " fig.ondownload(fig, null);\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(\n",
+ " 'matplotlib',\n",
+ " mpl.mpl_figure_comm\n",
+ " );\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig=plt.figure(figsize=(9,6))\n",
+ "fig.subplots_adjust(bottom=0.05, left=0.1, top = 0.99, right=0.9,wspace=0.0,hspace=0.15)\n",
+ "fig.suptitle('')\n",
+ "\n",
+ "\n",
+ "\n",
+ "_c=['xkcd:black','xkcd:red','xkcd:blue']\n",
+ "sub = fig.add_subplot(311)\n",
+ "\n",
+ "sub.plot(t,y1,c=_c[0],alpha=0.5,linestyle='-',linewidth=3,label=r'$y_{1}(t)$')\n",
+ "sub.plot(t,y2,c=_c[1],alpha=0.5,linestyle='-',linewidth=3,label=r'$y_{2}(t)$')\n",
+ "sub.plot(t,y3,c=_c[2],alpha=0.5,linestyle='-',linewidth=3,label=r'$y_{3}(t)$')\n",
+ "\n",
+ "\n",
+ "sub.plot(t_py,y_py[:,0],c=_c[0],alpha=1,linestyle=':',linewidth=2,label=r'$y_{1}(t)$ scipy')\n",
+ "sub.plot(t_py,y_py[:,1],c=_c[1],alpha=1,linestyle=':',linewidth=2,label=r'$y_{2}(t)$ scipy')\n",
+ "sub.plot(t_py,y_py[:,2],c=_c[2],alpha=1,linestyle=':',linewidth=2,label=r'$y_{3}(t)$ scipy')\n",
+ "\n",
+ "# sub.plot(t,sol_ode[:,0],c=_c[0],alpha=1,linestyle='--',linewidth=2,label=r'$y_{1}(t)$ scipy-odeint')\n",
+ "# sub.plot(t,sol_ode[:,1],c=_c[1],alpha=1,linestyle='--',linewidth=2,label=r'$y_{2}(t)$ scipy-odeint')\n",
+ "# sub.plot(t,sol_ode[:,2],c=_c[2],alpha=1,linestyle='--',linewidth=2,label=r'$y_{3}(t)$ scipy-odeint')\n",
+ "\n",
+ "\n",
+ "sub.legend(framealpha=0,ncol=2,loc='upper right',bbox_to_anchor=(1,.9))\n",
+ "sub.set_xscale('log')\n",
+ "# sub.set_yscale('log')\n",
+ "\n",
+ "sub.set_ylabel('y') \n",
+ "# sub.set_xlim(0,1) \n",
+ "\n",
+ "\n",
+ "\n",
+ "sub = fig.add_subplot(312) \n",
+ "sub.hist(np.log10(t[1:]),color=_c[0],label=r'mine',bins=25 )\n",
+ "# sub.plot(t,hist)\n",
+ "# sub.set_xscale('log')\n",
+ "\n",
+ "sub.set_ylabel('No. steps')\n",
+ "\n",
+ "\n",
+ "sub = fig.add_subplot(313) \n",
+ "sub.plot(t,np.abs(err1/y1),c=_c[0],alpha=1,linestyle='--',linewidth=3,label=r'$y_{1}(t)$')\n",
+ "sub.plot(t,np.abs(err2/y2),c=_c[1],alpha=1,linestyle='--',linewidth=3,label=r'$y_{2}(t)$')\n",
+ "sub.plot(t,np.abs(err3/y3),c=_c[2],alpha=1,linestyle='--',linewidth=3,label=r'$y_{3}(t)$')\n",
+ "sub.legend(framealpha=0,ncol=2,loc='upper right',bbox_to_anchor=(1,.9))\n",
+ "\n",
+ "sub.set_yscale('log')\n",
+ "sub.set_xscale('log')\n",
+ "\n",
+ "sub.set_ylabel(r' $\\dfrac{\\Delta y}{ y} $ ')\n",
+ "sub.set_xlabel('t') \n",
+ "\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "/* global mpl */\n",
+ "window.mpl = {};\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(\n",
+ " '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",
+ "\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 = document.createElement('div');\n",
+ " this.root.setAttribute('style', 'display: inline-block');\n",
+ " this._root_extra_style(this.root);\n",
+ "\n",
+ " parent_element.appendChild(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 (fig.ratio !== 1) {\n",
+ " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.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 = document.createElement('div');\n",
+ " titlebar.classList =\n",
+ " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
+ " var titletext = document.createElement('div');\n",
+ " titletext.classList = 'ui-dialog-title';\n",
+ " titletext.setAttribute(\n",
+ " 'style',\n",
+ " 'width: 100%; text-align: center; padding: 3px;'\n",
+ " );\n",
+ " titlebar.appendChild(titletext);\n",
+ " this.root.appendChild(titlebar);\n",
+ " this.header = titletext;\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
+ "\n",
+ "mpl.figure.prototype._init_canvas = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
+ " canvas_div.setAttribute(\n",
+ " 'style',\n",
+ " 'border: 1px solid #ddd;' +\n",
+ " 'box-sizing: content-box;' +\n",
+ " 'clear: both;' +\n",
+ " 'min-height: 1px;' +\n",
+ " 'min-width: 1px;' +\n",
+ " 'outline: 0;' +\n",
+ " 'overflow: hidden;' +\n",
+ " 'position: relative;' +\n",
+ " 'resize: both;'\n",
+ " );\n",
+ "\n",
+ " function on_keyboard_event_closure(name) {\n",
+ " return function (event) {\n",
+ " return fig.key_event(event, name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " canvas_div.addEventListener(\n",
+ " 'keydown',\n",
+ " on_keyboard_event_closure('key_press')\n",
+ " );\n",
+ " canvas_div.addEventListener(\n",
+ " 'keyup',\n",
+ " on_keyboard_event_closure('key_release')\n",
+ " );\n",
+ "\n",
+ " this._canvas_extra_style(canvas_div);\n",
+ " this.root.appendChild(canvas_div);\n",
+ "\n",
+ " var canvas = (this.canvas = document.createElement('canvas'));\n",
+ " canvas.classList.add('mpl-canvas');\n",
+ " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
+ "\n",
+ " this.context = canvas.getContext('2d');\n",
+ "\n",
+ " var backingStore =\n",
+ " this.context.backingStorePixelRatio ||\n",
+ " this.context.webkitBackingStorePixelRatio ||\n",
+ " this.context.mozBackingStorePixelRatio ||\n",
+ " this.context.msBackingStorePixelRatio ||\n",
+ " this.context.oBackingStorePixelRatio ||\n",
+ " this.context.backingStorePixelRatio ||\n",
+ " 1;\n",
+ "\n",
+ " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
+ " 'canvas'\n",
+ " ));\n",
+ " rubberband_canvas.setAttribute(\n",
+ " 'style',\n",
+ " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
+ " );\n",
+ "\n",
+ " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
+ " if (this.ResizeObserver === undefined) {\n",
+ " if (window.ResizeObserver !== undefined) {\n",
+ " this.ResizeObserver = window.ResizeObserver;\n",
+ " } else {\n",
+ " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
+ " this.ResizeObserver = obs.ResizeObserver;\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
+ " var nentries = entries.length;\n",
+ " for (var i = 0; i < nentries; i++) {\n",
+ " var entry = entries[i];\n",
+ " var width, height;\n",
+ " if (entry.contentBoxSize) {\n",
+ " if (entry.contentBoxSize instanceof Array) {\n",
+ " // Chrome 84 implements new version of spec.\n",
+ " width = entry.contentBoxSize[0].inlineSize;\n",
+ " height = entry.contentBoxSize[0].blockSize;\n",
+ " } else {\n",
+ " // Firefox implements old version of spec.\n",
+ " width = entry.contentBoxSize.inlineSize;\n",
+ " height = entry.contentBoxSize.blockSize;\n",
+ " }\n",
+ " } else {\n",
+ " // Chrome <84 implements even older version of spec.\n",
+ " width = entry.contentRect.width;\n",
+ " height = entry.contentRect.height;\n",
+ " }\n",
+ "\n",
+ " // Keep the size of the canvas and rubber band canvas in sync with\n",
+ " // the canvas container.\n",
+ " if (entry.devicePixelContentBoxSize) {\n",
+ " // Chrome 84 implements new version of spec.\n",
+ " canvas.setAttribute(\n",
+ " 'width',\n",
+ " entry.devicePixelContentBoxSize[0].inlineSize\n",
+ " );\n",
+ " canvas.setAttribute(\n",
+ " 'height',\n",
+ " entry.devicePixelContentBoxSize[0].blockSize\n",
+ " );\n",
+ " } else {\n",
+ " canvas.setAttribute('width', width * fig.ratio);\n",
+ " canvas.setAttribute('height', height * fig.ratio);\n",
+ " }\n",
+ " canvas.setAttribute(\n",
+ " 'style',\n",
+ " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
+ " );\n",
+ "\n",
+ " rubberband_canvas.setAttribute('width', width);\n",
+ " rubberband_canvas.setAttribute('height', height);\n",
+ "\n",
+ " // And update the size in Python. We ignore the initial 0/0 size\n",
+ " // that occurs as the element is placed into the DOM, which should\n",
+ " // otherwise not happen due to the minimum size styling.\n",
+ " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
+ " fig.request_resize(width, height);\n",
+ " }\n",
+ " }\n",
+ " });\n",
+ " this.resizeObserverInstance.observe(canvas_div);\n",
+ "\n",
+ " function on_mouse_event_closure(name) {\n",
+ " return function (event) {\n",
+ " return fig.mouse_event(event, name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mousedown',\n",
+ " on_mouse_event_closure('button_press')\n",
+ " );\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseup',\n",
+ " on_mouse_event_closure('button_release')\n",
+ " );\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mousemove',\n",
+ " on_mouse_event_closure('motion_notify')\n",
+ " );\n",
+ "\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseenter',\n",
+ " on_mouse_event_closure('figure_enter')\n",
+ " );\n",
+ " rubberband_canvas.addEventListener(\n",
+ " 'mouseleave',\n",
+ " on_mouse_event_closure('figure_leave')\n",
+ " );\n",
+ "\n",
+ " canvas_div.addEventListener('wheel', function (event) {\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " on_mouse_event_closure('scroll')(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.appendChild(canvas);\n",
+ " canvas_div.appendChild(rubberband_canvas);\n",
+ "\n",
+ " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
+ " this.rubberband_context.strokeStyle = '#000000';\n",
+ "\n",
+ " this._resize_canvas = function (width, height, forward) {\n",
+ " if (forward) {\n",
+ " canvas_div.style.width = width + 'px';\n",
+ " canvas_div.style.height = height + 'px';\n",
+ " }\n",
+ " };\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
+ " event.preventDefault();\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 toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'mpl-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'mpl-button-group';\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'mpl-button-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " var button = (fig.buttons[name] = document.createElement('button'));\n",
+ " button.classList = 'mpl-widget';\n",
+ " button.setAttribute('role', 'button');\n",
+ " button.setAttribute('aria-disabled', 'false');\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ "\n",
+ " var icon_img = document.createElement('img');\n",
+ " icon_img.src = '_images/' + image + '.png';\n",
+ " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
+ " icon_img.alt = tooltip;\n",
+ " button.appendChild(icon_img);\n",
+ "\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker = document.createElement('select');\n",
+ " fmt_picker.classList = 'mpl-widget';\n",
+ " toolbar.appendChild(fmt_picker);\n",
+ " this.format_dropdown = fmt_picker;\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = document.createElement('option');\n",
+ " option.selected = fmt === mpl.default_extension;\n",
+ " option.innerHTML = fmt;\n",
+ " fmt_picker.appendChild(option);\n",
+ " }\n",
+ "\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\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",
+ "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",
+ "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], msg['forward']);\n",
+ " fig.send_message('refresh', {});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
+ " var x0 = msg['x0'] / fig.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
+ " var x1 = msg['x1'] / fig.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / fig.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,\n",
+ " 0,\n",
+ " fig.canvas.width / fig.ratio,\n",
+ " fig.canvas.height / fig.ratio\n",
+ " );\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",
+ " 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.handle_history_buttons = function (fig, msg) {\n",
+ " for (var key in msg) {\n",
+ " if (!(key in fig.buttons)) {\n",
+ " continue;\n",
+ " }\n",
+ " fig.buttons[key].disabled = !msg[key];\n",
+ " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
+ " if (msg['mode'] === 'PAN') {\n",
+ " fig.buttons['Pan'].classList.add('active');\n",
+ " fig.buttons['Zoom'].classList.remove('active');\n",
+ " } else if (msg['mode'] === 'ZOOM') {\n",
+ " fig.buttons['Pan'].classList.remove('active');\n",
+ " fig.buttons['Zoom'].classList.add('active');\n",
+ " } else {\n",
+ " fig.buttons['Pan'].classList.remove('active');\n",
+ " fig.buttons['Zoom'].classList.remove('active');\n",
+ " }\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",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data\n",
+ " );\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " } else if (\n",
+ " typeof evt.data === 'string' &&\n",
+ " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
+ " ) {\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(\n",
+ " \"No handler for the '\" + msg_type + \"' message type: \",\n",
+ " msg\n",
+ " );\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(\n",
+ " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
+ " e,\n",
+ " e.stack,\n",
+ " msg\n",
+ " );\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",
+ " }\n",
+ " if (e.target) {\n",
+ " targ = e.target;\n",
+ " } else if (e.srcElement) {\n",
+ " targ = e.srcElement;\n",
+ " }\n",
+ " if (targ.nodeType === 3) {\n",
+ " // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ " }\n",
+ "\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " var boundingRect = targ.getBoundingClientRect();\n",
+ " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
+ " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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",
+ " }\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",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * this.ratio;\n",
+ " var y = canvas_pos.y * this.ratio;\n",
+ "\n",
+ " this.send_message(name, {\n",
+ " x: x,\n",
+ " y: y,\n",
+ " button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event),\n",
+ " });\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",
+ " // Prevent repeat events\n",
+ " if (name === 'key_press') {\n",
+ " if (event.which === this._key) {\n",
+ " return;\n",
+ " } else {\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " }\n",
+ " if (name === 'key_release') {\n",
+ " this._key = null;\n",
+ " }\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which !== 17) {\n",
+ " value += 'ctrl+';\n",
+ " }\n",
+ " if (event.altKey && event.which !== 18) {\n",
+ " value += 'alt+';\n",
+ " }\n",
+ " if (event.shiftKey && event.which !== 16) {\n",
+ " value += 'shift+';\n",
+ " }\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, 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",
+ "\n",
+ "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
+ "// prettier-ignore\n",
+ "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n",
+ "\n",
+ "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 = document.getElementById(id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm);\n",
+ "\n",
+ " function ondownload(figure, _format) {\n",
+ " window.open(figure.canvas.toDataURL());\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n",
+ " fig.cell_info = mpl.find_output_cell(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error('Failed to find cell for figure', id, fig);\n",
+ " return;\n",
+ " }\n",
+ " fig.cell_info[0].output_area.element.on(\n",
+ " 'cleared',\n",
+ " { fig: fig },\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
+ " var width = fig.canvas.width / fig.ratio;\n",
+ " fig.cell_info[0].output_area.element.off(\n",
+ " 'cleared',\n",
+ " fig._remove_fig_handler\n",
+ " );\n",
+ " fig.resizeObserverInstance.unobserve(fig.canvas_div);\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.innerHTML =\n",
+ " '';\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 / this.ratio;\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] =\n",
+ " '';\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 () {\n",
+ " fig.push_to_output();\n",
+ " }, 1000);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function () {\n",
+ " var fig = this;\n",
+ "\n",
+ " var toolbar = document.createElement('div');\n",
+ " toolbar.classList = 'btn-toolbar';\n",
+ " this.root.appendChild(toolbar);\n",
+ "\n",
+ " function on_click_closure(name) {\n",
+ " return function (_event) {\n",
+ " return fig.toolbar_button_onclick(name);\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " function on_mouseover_closure(tooltip) {\n",
+ " return function (event) {\n",
+ " if (!event.currentTarget.disabled) {\n",
+ " return fig.toolbar_button_onmouseover(tooltip);\n",
+ " }\n",
+ " };\n",
+ " }\n",
+ "\n",
+ " fig.buttons = {};\n",
+ " var buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " var button;\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",
+ " /* Instead of a spacer, we start a new button group. */\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ " buttonGroup = document.createElement('div');\n",
+ " buttonGroup.classList = 'btn-group';\n",
+ " continue;\n",
+ " }\n",
+ "\n",
+ " button = fig.buttons[name] = document.createElement('button');\n",
+ " button.classList = 'btn btn-default';\n",
+ " button.href = '#';\n",
+ " button.title = name;\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', on_click_closure(method_name));\n",
+ " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
+ " buttonGroup.appendChild(button);\n",
+ " }\n",
+ "\n",
+ " if (buttonGroup.hasChildNodes()) {\n",
+ " toolbar.appendChild(buttonGroup);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = document.createElement('span');\n",
+ " status_bar.classList = 'mpl-message pull-right';\n",
+ " toolbar.appendChild(status_bar);\n",
+ " this.message = status_bar;\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = document.createElement('div');\n",
+ " buttongrp.classList = 'btn-group inline pull-right';\n",
+ " button = document.createElement('button');\n",
+ " button.classList = 'btn btn-mini btn-primary';\n",
+ " button.href = '#';\n",
+ " button.title = 'Stop Interaction';\n",
+ " button.innerHTML = '';\n",
+ " button.addEventListener('click', function (_evt) {\n",
+ " fig.handle_close(fig, {});\n",
+ " });\n",
+ " button.addEventListener(\n",
+ " 'mouseover',\n",
+ " on_mouseover_closure('Stop Interaction')\n",
+ " );\n",
+ " buttongrp.appendChild(button);\n",
+ " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
+ " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
+ " var fig = event.data.fig;\n",
+ " if (event.target !== this) {\n",
+ " // Ignore bubbled events from children.\n",
+ " return;\n",
+ " }\n",
+ " fig.close_ws(fig, {});\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function (el) {\n",
+ " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
+ " // this is important to make the div 'focusable\n",
+ " el.setAttribute('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",
+ " } else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\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",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which === 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
+ " fig.ondownload(fig, null);\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(\n",
+ " 'matplotlib',\n",
+ " mpl.mpl_figure_comm\n",
+ " );\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig=plt.figure(figsize=(8,4))\n",
+ "fig.subplots_adjust(bottom=0.15, left=0.1, top = 0.99, right=0.9,wspace=0.0,hspace=0.2)\n",
+ "fig.suptitle('')\n",
+ "\n",
+ "\n",
+ "\n",
+ "_c=['xkcd:black','xkcd:red','xkcd:blue']\n",
+ "sub = fig.add_subplot(111)\n",
+ "\n",
+ "sub.hist(np.log10(t[1:]),color=_c[0],label=r'mine',bins=25 )\n",
+ "sub.hist(np.log10(t_py[1:]),color=_c[2],label=r'scipy',alpha=0.5,bins=25)\n",
+ "\n",
+ "# check also this\n",
+ "# sub.plot(t,hist,label=r'mine')\n",
+ "# sub.hist(t_py,label=r'scipy',alpha=0.5,bins=N)\n",
+ "\n",
+ "\n",
+ "\n",
+ "sub.set_ylabel('No. steps')\n",
+ "\n",
+ "\n",
+ "sub.legend(framealpha=0,ncol=2,loc='upper right',bbox_to_anchor=(1,.9))\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "455"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(t)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "305"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(t_py)"
+ ]
+ },
+ {
+ "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.9.1"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/src/NaBBODES/Rosenbrock/Example.cpp b/src/NaBBODES/Rosenbrock/Example.cpp
new file mode 100644
index 0000000..8d63a6f
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Example.cpp
@@ -0,0 +1,85 @@
+// This is how you run Rosenbrock, using a functor
+#include
+#include
+#include
+#include"Ros.hpp"
+#include "Jacobian/Jacobian.hpp"//this is treated as user input, since one may have an analytic form.
+#include "METHOD.hpp"
+
+using std::cout;
+using std::endl;
+/*--------------------------------------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------------------------------------*/
+#ifndef LONG
+#define LONG
+#endif
+
+
+#define LD LONG double
+
+
+#ifndef METHOD
+#define METHOD ROS34PW2
+#endif
+
+
+#define initial_step_size 1e-2
+#define minimum_step_size 1e-8
+#define maximum_step_size 1e3
+#define maximum_No_steps 1000000
+#define absolute_tolerance 1e-8
+#define relative_tolerance 1e-8
+#define beta 0.5
+#define fac_max 1.01
+#define fac_min 0.9
+
+// this is how the diffeq should look like
+#define n_eqs 1 //number of equations
+using Array = std::array;//define an array type of length n_eqs
+//-------------------------------------------------------------------------//
+
+using std::pow;
+
+
+// you can use a function, but with a class you can also hold data that can be useful.
+class diffeq{
+ public:
+ LD c;
+ diffeq(LD c):c(c){};
+
+ void operator()(Array &lhs, Array &y , LD t){
+ lhs[0]=t*c;
+ }
+
+};
+
+
+
+using SOLVER = Ros ,Jacobian , LD>;
+
+int main(int argc, const char** argv) {
+
+ Array y0 = {2};
+ diffeq dydt(2);
+
+
+ SOLVER System(dydt,y0, 1e4,
+ initial_step_size, minimum_step_size, maximum_step_size, maximum_No_steps,
+ absolute_tolerance, relative_tolerance, beta, fac_max, fac_min);
+
+ System.solve();
+ // return 0;
+
+ int step=0;
+ for (auto _t: System.time){
+ printf("%e ",(double)_t);
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e ", (double)System.solution[eq][step]);}
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e " ,(double)System.error[eq][step]);}
+ printf("\n");
+ step++;
+ }
+
+
+ return 0;
+ }
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/Jacobian/Jacobian.hpp b/src/NaBBODES/Rosenbrock/Jacobian/Jacobian.hpp
new file mode 100755
index 0000000..fd11a63
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Jacobian/Jacobian.hpp
@@ -0,0 +1,75 @@
+#ifndef Jac_head
+#define Jac_head
+#include
+#include
+// This is an example Jacobian class.
+
+
+template
+class Jacobian{
+ using diffeq = std::function &lhs, std::array &y , LD t)>;
+ public:
+ LD h;
+ diffeq dydt;
+
+ std::array y0,y1,dydt0,dydt1;
+
+ Jacobian()=default;
+
+ // It is good to have a copy contructor is needed here, in case you need it.
+ // Rosenbrock works without it, but may be useful in the future.
+ Jacobian(Jacobian &Jac){
+ this->dydt=Jac.dydt;
+ this->h=Jac.h;
+ };
+
+ Jacobian(diffeq dydt, LD h=1e-10){
+ this->dydt=dydt;
+ this->h=h;
+
+ };
+
+ Jacobian& operator=(const Jacobian &Jac){
+ this->dydt=Jac.dydt;
+ this->h=Jac.h;
+ return *this;
+ }
+
+ void operator()(std::array, N_eqs> &J, std::array &dfdt, std::array &y , LD t ){
+ // you can use something like this to scale the stepsize according to the scale of t
+ LD a=this->h+this->h*t;
+ // take the time derivative
+ dydt(dydt0,y,t-a);
+ dydt(dydt1,y,t+a);
+ for (int i = 0; i < N_eqs; i++){ dfdt[i]=(dydt1[i]-dydt0[i])/(2*a); }
+
+ // take the derivatives over y
+ for (int i = 0; i < N_eqs; i++){
+ for (int j = 0; j < N_eqs; j++){
+ for(int _d = 0; _d < N_eqs; _d++){y0[_d]=y[_d]; y1[_d]=y[_d]; }
+ // you can use something like this to scale the stepsize according to the scale of y[j]
+ a=this->h+this->h*std::abs(y0[j]);
+
+ y0[j]=y0[j]-a;
+ y1[j]=y1[j]+a;
+ dydt(dydt0,y0,t);
+ dydt(dydt1,y1,t);
+
+ J[i][j]=(dydt1[i]-dydt0[i])/(2*a);
+ // if(isnan(J[i][j])){J[i][j]=0;}
+ }
+ }
+
+
+
+
+ };
+
+
+
+
+
+};
+
+
+#endif
diff --git a/src/NaBBODES/Rosenbrock/Jacobian/a.out b/src/NaBBODES/Rosenbrock/Jacobian/a.out
new file mode 100755
index 0000000..2fd8ab7
Binary files /dev/null and b/src/NaBBODES/Rosenbrock/Jacobian/a.out differ
diff --git a/src/NaBBODES/Rosenbrock/Jacobian/test-Jac.cpp b/src/NaBBODES/Rosenbrock/Jacobian/test-Jac.cpp
new file mode 100755
index 0000000..8b3f860
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Jacobian/test-Jac.cpp
@@ -0,0 +1,91 @@
+#include
+#include
+#include"Jacobian.hpp"
+// #define _class //run it with class with overloaded operator()
+#define _function //run it with function pointer
+
+#define LD double
+
+
+// this is how the diffeq should look like
+#define n_eqs 2 //number of equations
+typedef std::array Array;//define an array type of length n_eqs
+typedef std::array Array2;
+//-------------------------------------------------------------------------//
+
+
+
+#ifdef _function
+typedef void (*diffeq)(Array &lhs, Array &y , LD t); // define function pointer
+void sys(Array &lhs, Array &y , LD t)
+{
+
+ lhs[0]=y[1]*y[0]*t;
+ lhs[1]=y[0]*y[1]+t;
+
+}
+#endif
+
+
+#ifdef _class
+class Cdiffeq{
+ public:
+ Cdiffeq(){};
+ ~Cdiffeq(){};
+ void operator()(Array &lhs, Array &y , LD t)
+ {
+ lhs[0]=y[1]*y[0]*t;
+ lhs[1]=y[0]*y[1]+t;
+ }
+
+
+};
+#endif
+
+
+using std::cout;
+using std::endl;
+
+
+int main(){
+ #ifdef _class
+ Cdiffeq dydt;
+ Jacobian jac(dydt);
+ #endif
+
+ #ifdef _function
+ Jacobian jac(sys);
+ #endif
+
+ Array dfdt;
+ // Matrix J={{0,0},{0,0}};
+ Array2 J;
+
+ Array y={1,4.2};
+ LD t=0.3;
+
+ jac(J,dfdt,y,t);
+
+ cout<<"dfdt=[";
+ for(int i=0; i
+#include
+
+/*---------------------Functions I need for LU decomposition-------------------------------------------------*/
+template
+unsigned int ind_max(std::array &row, unsigned int len_col){
+ /*
+ Find the index of the maximum of a list (row) of lentgth N up to len_col.
+ */
+ int _in=0;
+ LD _max = std::abs(row[0]);
+
+ for (unsigned int i = 1; i < len_col; i++)
+ {
+ if(std::abs(row[i])>_max){_max=std::abs(row[i]); _in=i; }
+ }
+
+
+ return _in;
+}
+
+
+
+
+template
+void index_swap(std::array &A, int index_1, int index_2){
+
+ /*
+ index_swap takes an array and interchanges
+ A[index_1] with A[index_2].
+ */
+ LD tmp=A[index_1];
+ A[index_1]=A[index_2];
+ A[index_2]=tmp;
+
+
+}
+
+template
+void index_swap(std::array &A, int index_1, int index_2){
+
+ /*
+ index_swap takes an array and interchanges
+ A[index_1] with A[index_2].
+ */
+ int tmp=A[index_1];
+ A[index_1]=A[index_2];
+ A[index_2]=tmp;
+
+
+}
+
+template
+void apply_permutations_vector(std::array &A, std::array &P, std::array &Ap){
+ /*
+ Applies the permutations given by P from LUP
+ to a list A of length N, and stores the result to Ap.
+
+ Example:
+ If we do this:
+
+ LD A[]={1,2,5,8,3};
+ int P[]={2,4,0,3,1};
+
+ LD Ap[5];
+ apply_permutations_vector(A,P,5,Ap)
+
+ we get Ap={5,3,1,8,2}
+ */
+
+ for (unsigned int i = 0; i < N; i++){Ap[i]=A[ P[i] ];}
+
+}
+
+template
+void Map( LD (*F)(LD) , std::array &L, std::array &FL){
+ for (unsigned int i = 0; i < N; i++){ FL[i] = F(L[i]); }
+
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
+
+/*-----------------------------LUP decompositioning--------------------------------------------------------*/
+
+template
+void LUP(std::array,N> &M, std::array,N> &L ,std::array,N> &U, std::array &P, LD _tiny=1e-25){
+
+ // Initialize LU
+ for (unsigned int i = 0; i < N; i++){
+ P[i]=i;
+ for (unsigned int j = 0; j < N; j++)
+ {
+ if(i==j){L[i][j]=1;}
+ if(i!=j){L[i][j]=0;}
+ U[i][j]=M[i][j];
+ }
+ }
+ std::array _col,tmpU,tmpL;
+ unsigned int len_col,pivot;
+
+
+ for (unsigned int k = 1; k < N; k++){ for ( unsigned int i = k; i < N; i++){
+ for (unsigned int _r=k-1 ; _r( _col,len_col) + k - 1;
+ // std::cout<(P,k-1,pivot);
+
+ for (unsigned int _r=k-1 ; _r
+void Solve_LU(std::array,N> &L,std::array,N> &U, std::array &P, std::array &b , std::array &x){
+ /*
+ This solves M*x=b
+ Input:
+ L,U,P= LUP decomposition of M, which is the output of the function LUP.
+
+ b=the right hand side of the equation
+ N=the number of equations
+
+ x=an array to store the solution of M*x=b
+ */
+
+ std::array d{0}, bp{0};
+ LD tmps=0;
+
+ apply_permutations_vector(b,P,bp);
+
+
+ d[0]=bp[0];
+
+ for(unsigned int i=1; i -1; i--)
+ {
+ tmps=0;
+ for (unsigned int j = i+1; j < N; j++){ tmps += U[i][j]*x[j]; }
+ x[i]=(d[i]-tmps )/U[i][i];
+ }
+
+}
+/*-------------------------------------------------------------------------------------------------------------------*/
+
+
+
+
+
+
+
+
+
+
+
+/*------------------------------------------------Solve-LU----------------------------------------------------------*/
+template
+void Inverse_LU(std::array,N> &L, std::array,N> &U, std::array &P, std::array,N> &invM){
+ /*
+ Finds the Inverse matrix given its LU decomposition.
+ Basically this solves M*M^{-1}=1
+
+ Input:
+ L,U,P= LUP decomposition of M, which is the output of the function LUP.
+
+ N=dimension of the matrix (N*N)
+
+ invM=an array to store the solution inverse matrix.
+ */
+
+ //
+ std::array e;
+ for(unsigned int i=0 ; i< N ; ++i){ e[i]=0; }
+ std::array x;
+
+ for(unsigned int i=0 ; i< N ; ++i){
+ e[i]=1;
+ Solve_LU(L,U,P,e,x);
+
+ for(unsigned int j=0 ; j
+void dot(std::array,N> &A, std::array,N> &B, std::array,N> &R){
+ /*
+ Calculates the product of two matrices.
+ R=A*B
+ */
+
+ for(unsigned int i=0; i
+void dot(std::array,N> &A, std::array &x, std::array &b){
+ /*
+ Calculates the product of matrix with vector.
+ b=A*x
+ */
+
+ for(unsigned int i=0; i
+#include
+#include
+#include "LU.hpp"
+
+using std::cout;
+using std::endl;
+
+#define LD double
+
+// #define indmax // run ind_max test
+
+// #define swap //run index_swap test
+
+// #define perm //run permutation test
+
+// #define lup //run LUP test
+
+// #define _rand //run random tests of Solve_LU
+
+// #define inv_test // random tests of Inverse_LU
+
+
+
+
+#ifdef _rand
+ #include
+#endif
+
+int main(){
+
+
+ #ifdef indmax
+ std::array x={2,1,-1,2,50};
+ cout<(x)< x={2,1,-1,2,50};
+ index_swap<5,LD>(x,4,1);
+ for( LD i : x ){ cout< A={1,2,5,8,3};
+ std::array P={2,4,0,3,1};
+
+ std::array Ap{0};
+
+ apply_permutations_vector(A,P,Ap);
+ for( int i =0 ; i<5 ; i++){ cout< ,N> M={{
+ { 0, 2, 2 , 3 , 5},
+ {-3, -1, 1 , 5 , 9},
+ { 1, -1, 1 , 4 , 7},
+ { 1, -1, 1 , 0 , 2},
+ { 1, -1, 1 , 0 , 3}
+ }};
+
+
+ std::array P;
+ std::array,N> L, U;
+
+ LUP(M,L,U,P);
+
+ for( LD i : P ){ cout<< i<<' ';}
+ cout< 1e-11, print it.
+ */
+ const unsigned int runs=100000;
+ std::array err;
+
+
+ const unsigned int N=10;
+ std::array,N> M,U,L;
+ std::array b,x;
+ std::array P;
+
+ std::array tmp;
+
+ LD tmpE;
+
+ for(unsigned int _r=0; _r(M,L,U,P);
+ Solve_LU(L,U,P,b,x);
+
+ err[_r]=0;
+ for (int i = 0; i < N; i++){
+ dot(M,x,tmp);
+ tmpE= std::abs((tmp[i] - b[i])/b[i]) ;
+ if(tmpE>err[_r] ) {err[_r] = tmpE ;}
+
+ }
+
+
+ }
+
+ for(LD _err: err){
+ if(_err>1e-11){ cout<<_err<1e-12, print it.
+ */
+
+
+ const unsigned int N=10;
+ std::array,N> M,L,U,invM,R;
+
+ std::array,N> Unit;
+ for (int i = 0; i < N; i++){
+ for (int j = 0; j < N; j++){
+ Unit[i][j]=0;
+ }
+ }
+
+
+ std::array P;
+ LD tmp;
+
+ for(int _run=0 ; _run<1000; ++_run)
+ {
+ for (int i = 0; i < N; i++)
+ {
+ // Unit is initialized as zero matrix. So put 1 at Unit[i][i].
+ Unit[i][i]=1;
+ for (int j = 0; j < N; j++)
+ {
+ // fil M with random numbers
+ M[i][j]= ( rand()/ ((LD) RAND_MAX ) -0.5 ) *100 ;
+
+ }
+ }
+
+ // LUP decomposition of M
+ LUP(M,L,U,P);
+ // Given LUP decomposition you can calculate the inverse.
+ Inverse_LU(L,U,P,invM);
+
+ // calculate M*M^{-1}
+ dot(M,invM,R);
+
+
+ // print if M*M^{-1} - 1 > 10^{-10}
+ for(int i=0; i1e-12){ cout<< tmp << endl;}
+ }
+ }
+ }
+ #endif
+
+
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/METHOD.hpp b/src/NaBBODES/Rosenbrock/METHOD.hpp
new file mode 100644
index 0000000..5c489cb
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/METHOD.hpp
@@ -0,0 +1,93 @@
+#ifndef Ros_METHOD
+#define Ros_METHOD
+#include
+
+template
+struct ROS3w{
+ static constexpr unsigned int s=3;
+ static constexpr unsigned int p=2;
+
+ using arr=std::array;
+ using arr2=std::array,s>;
+
+ static constexpr arr c={0,2/3.,4/3.};
+ static constexpr arr b={0.25,0.25,0.5 };
+ static constexpr arr bstar={ 0.746704703274 , 0.1144064078371 , 0.1388888888888 };
+ static constexpr LD gamma=0.4358665215084;
+
+ static constexpr arr2 a={
+ arr{0,0,0},
+ arr{2/3.,0,0},
+ arr{2/3.,2/3.,0}
+
+ };
+
+ static constexpr arr2 g={
+ arr{0,0,0},
+ arr{0.3635068368900,0,0},
+ arr{-0.8996866791992,-0.1537997822626,0}
+
+ };
+};
+/*--------------------------------------------------------------------------------------------------------*/
+template
+struct ROS34PW2{
+ static constexpr unsigned int s=4;
+ static constexpr unsigned int p=3;
+
+ using arr=std::array;
+ using arr2=std::array,s>;
+
+ static constexpr arr c={0, 0.87173304301691800777, 0.73157995778885237526, 1};// c[i]=sum_{j} a[i][j]
+ static constexpr arr b={2.4212380706095346e-1 , -1.2232505839045147 , 1.5452602553351020 , 4.3586652150845900e-1};
+ static constexpr arr bstar={ 3.7810903145819369e-1 , -9.6042292212423178e-2 , 0.5 , 2.1793326075422950e-1};
+ static constexpr LD gamma=4.3586652150845900e-1;
+
+ static constexpr arr2 a={
+ arr{0,0,0,0},
+ arr{8.7173304301691801e-1,0,0,0},
+ arr{8.4457060015369423e-1,-1.1299064236484185e-1,0,0},
+ arr{0,0,1,0}
+ };
+
+ static constexpr arr2 g={
+ arr{0,0,0,0},
+ arr{-8.7173304301691801e-1,0,0,0},
+ arr{-9.0338057013044082e-1,5.4180672388095326e-2,0,0},
+ arr{2.4212380706095346e-1,-1.2232505839045147,5.4526025533510214e-1,0}
+ };
+};
+/*--------------------------------------------------------------------------------------------------------*/
+template
+struct RODASPR2{
+ static constexpr unsigned int s=6;
+ static constexpr unsigned int p=4;
+
+ using arr=std::array;
+ using arr2=std::array,s>;
+
+ static constexpr arr c={0, 0.9375, 0.49816697385844987966, 0.68907842168064792343, 0.99999999999999997224, 0.99999999999999991673};// c[i]=sum_{j} a[i][j]
+ static constexpr arr b={5.1944159827788361e-1,3.9955867781540699e-2,-4.7356407303732290e-1,9.4907420451383284e-1,-3.4740759753593431e-1,3.125e-1 };
+ static constexpr arr bstar={-1.7746585073632790e-1,-5.8241418952602364e-1,6.8180612588238165e-1,7.6557391437996980e-1,3.125e-1,0 };
+ static constexpr LD gamma=3.125e-1;
+
+ static constexpr arr2 a={
+ arr{0,0,0,0,0,0},
+ arr{9.375e-1,0,0,0,0,0},
+ arr{-4.7145892646261345e-2,5.4531286650471122e-1,0,0,0,0},
+ arr{4.6915543899742240e-1,4.4490537602383673e-1,-2.2498239334061121e-1 ,0,0,0},
+ arr{1.0950372887345903,6.3223023457294381e-1,-8.9232966090485821e-01,1.6506213759732410e-1,0,0},
+ arr{-1.7746585073632790e-1,-5.8241418952602364e-1,6.8180612588238165e-1,7.6557391437996980e-1,3.125e-1,0}
+ };
+
+ static constexpr arr2 g={
+ arr{0,0,0,0,0,0},
+ arr{-9.3750000000000000e-01,0,0,0,0,0},
+ arr{-9.7580572085994507e-02,-5.8666328499964138e-01,0,0,0,0},
+ arr{-4.9407065013256957e-01,-5.6819726428975503e-01,5.0318949274167679e-01,0,0,0},
+ arr{-1.2725031394709183,-1.2146444240989676,1.5741357867872399,6.0051177678264578e-01,0,0},
+ arr{6.9690744901421153e-01,6.2237005730756434e-01,-1.1553701989197045,1.8350029013386296e-01,-6.5990759753593431e-01,0}
+ };
+};
+
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/Ros.cpp b/src/NaBBODES/Rosenbrock/Ros.cpp
new file mode 100644
index 0000000..e588056
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros.cpp
@@ -0,0 +1,86 @@
+// This is how you run RK.
+#include
+#include
+#include
+#include"Ros.hpp"
+#include "Jacobian/Jacobian.hpp"//this is treated as user input, since one may have an analytic form.
+#include "METHOD.hpp"
+
+using std::cout;
+using std::endl;
+/*--------------------------------------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------------------------------------*/
+#ifndef LONG
+#define LONG
+#endif
+
+
+#define LD LONG double
+
+
+#ifndef METHOD
+#define METHOD ROS34PW2
+#endif
+
+
+#define initial_step_size 1e-2
+#define minimum_step_size 1e-8
+#define maximum_step_size 1e4
+#define maximum_No_steps 1000000
+#define absolute_tolerance 1e-8
+#define relative_tolerance 1e-8
+#define beta 0.95
+#define fac_max 1.1
+#define fac_min 0.7
+
+// this is how the diffeq should look like
+#define n_eqs 3 //number of equations
+using Array = std::array;//define an array type of length n_eqs
+//-------------------------------------------------------------------------//
+
+using std::pow;
+
+
+// you can use a function, but with a class you can also hold data that can be useful.
+class diffeq{
+ public:
+ diffeq(){};
+ ~diffeq(){};
+
+ void operator()(Array &lhs, Array &y , LD t){
+ lhs[0]=-2*y[0]*pow(t,2) ;
+ lhs[1]=2*y[0]*pow(t,2)+2*(-pow( y[1],2 )+pow( y[2],2 ) )*pow(t,1);
+ lhs[2]=4*y[0]*pow(t,2)+2*(pow( y[1],2 )-pow( y[2],2 ) )*pow(t,1);
+ }
+
+};
+
+
+
+using SOLVER = Ros ,Jacobian , LD>;
+
+int main(int argc, const char** argv) {
+
+ Array y0 = {8,12,4};
+ diffeq dydt;
+
+ SOLVER System(dydt,y0, 1e4,
+ initial_step_size, minimum_step_size, maximum_step_size, maximum_No_steps,
+ absolute_tolerance, relative_tolerance, beta, fac_max, fac_min);
+
+ System.solve();
+ // return 0;
+
+ int step=0;
+ for (auto _t: System.time){
+ printf("%e ",(double)_t);
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e ", (double)System.solution[eq][step]);}
+ for( unsigned int eq = 0; eq < n_eqs; eq++){ printf("%e " ,(double)System.error[eq][step]);}
+ printf("\n");
+ step++;
+ }
+
+
+ return 0;
+ }
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/Ros.hpp b/src/NaBBODES/Rosenbrock/Ros.hpp
new file mode 100644
index 0000000..a4782f3
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros.hpp
@@ -0,0 +1,16 @@
+#ifndef Ros_headers
+#define Ros_headers
+#include "LU/LU.hpp"
+
+
+#include "Ros_class.hpp"
+#include "Ros_costructor.hpp"
+#include "Jacobian.hpp"
+#include "Ros_LU.hpp"
+#include "Ros_calc_k.hpp"
+#include "Ros_sums.hpp"
+// #include "Ros_step_control-simple.hpp"
+#include "Ros_step_control-PI.hpp"
+#include "Ros_steps.hpp"
+
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/Ros_LU.hpp b/src/NaBBODES/Rosenbrock/Ros_LU.hpp
new file mode 100644
index 0000000..638daaa
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_LU.hpp
@@ -0,0 +1,36 @@
+#ifndef Ros_LU
+#define Ros_LU
+#include "Ros_class.hpp"
+
+
+
+/*--------Calculate the LU decomposition of (1-h*gamma*J) for this step--------------------------*/
+template
+
+void Ros::LU(){
+ //initialize coefficient to 0
+ std::array, N_eqs> coeff;
+ coeff.fill({});
+
+ Jac(J,dfdt,yprev,tn);
+
+ // Find the LUP decomposition of (I-\gamma*h*J)
+ for(unsigned int i=0; i(coeff,L,U,P); //LU decomposition of (1-h*gamma*J)
+ Inverse_LU(L,U,P,_inv); // the inverse of (1-h*gamma*J)
+}
+/*---------------------------------------------------------------------------------------------*/
+
+
+
+
+
+
+
+
+#endif
diff --git a/src/NaBBODES/Rosenbrock/Ros_calc_k.hpp b/src/NaBBODES/Rosenbrock/Ros_calc_k.hpp
new file mode 100644
index 0000000..3448375
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_calc_k.hpp
@@ -0,0 +1,60 @@
+#ifndef Ros_calc_k
+#define Ros_calc_k
+#include "Ros_class.hpp"
+
+
+
+
+/*-----------------------Begin: calc_Jk---------------------------------*/
+template
+void Ros::calc_Jk(){
+ /*
+ Calculate product of matrix with vector.
+ We use it to get J*gk.
+ */
+ for(unsigned int i=0; i
+
+void Ros::calc_k(){
+ // since LU decomposition is not updated as you try to find suitable step, put it ouside the step control loop (should be faster)!
+ // LU();
+ // calculate k for the other stages
+ std::array yn;
+ // rhs is the rhs side of the equation to be solved by LU.
+ std::array rhs;
+ // to make it more clear, we are going to separate the rhs in three different parts
+ std::array rhs1,rhs2;
+
+ for(unsigned int stage = 0; stage < RK_method::s; stage++){
+ sum_ak(stage);
+ sum_gk(stage);
+ // setup the argument for dydt (it is evaluated at y_n+\sum a*k )
+ for(unsigned int eq=0; eq(L,U,P,rhs, lu_sol);
+
+ dot(_inv,rhs, lu_sol);
+ for(unsigned int eq = 0; eq < N_eqs; eq++ ){ k[eq][stage]=lu_sol[eq]; }
+ }
+}
+/*-----------------------End: calc_k---------------------------------*/
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/Ros_class.hpp b/src/NaBBODES/Rosenbrock/Ros_class.hpp
new file mode 100644
index 0000000..aa4fa73
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_class.hpp
@@ -0,0 +1,103 @@
+#ifndef Ros_class
+#define Ros_class
+
+#include
+#include
+#include
+
+/*
+N_eqs is ten number of equations to be solved RK_method
+is the method
+*/
+
+//This is a general implementation of explicit embedded RK solver of
+// a system of differential equations in the interval [0,tmax].
+
+
+
+
+template
+//Note that you can use template to pass the method
+class Ros{
+ private:
+ using diffeq = std::function &lhs, std::array &y , LD t)>;
+ diffeq dydt;
+ jacobian Jac;
+ LD hmin, hmax, abs_tol, rel_tol, beta, fac_max, fac_min;
+ unsigned int max_N;
+ LD h_old,delta_acc,delta_rej;//these will be initialized at the beginning of next_step
+ bool h_stop;//h_stop becomes true when suitable stepsize is found.
+
+ public:
+
+ LD tmax, h, tn;
+ std::array yprev;// previously accepted step. maybe the name is not good.
+
+
+ std::vector time;
+ std::array, N_eqs> solution;
+ std::array, N_eqs> error;
+
+
+ //these are here to hold the k's, sum_i b_i*k_i, sum_i b_i^{\star}*k_i, and sum_j a_{ij}*k_j
+ std::array,N_eqs> k;
+ std::array ak,gk,Jk, bk,bstark;
+ // need this to store the sum over \gammas (see the contructor)
+ std::array sum_gamma;
+ // abs_delta=abs(ynext-ynext_star)
+ std::array abs_delta;
+
+
+
+ std::array ynext;//this is here to hold the prediction
+ std::array ynext_star;//this is here to hold the second prediction
+
+
+
+ /*--These are specific to Rosenbrock methods*/
+ std::array dfdt;
+ //define the coefficient. This will become (I-\gamma*h*J). _inv is its inverse
+ std::array, N_eqs> _inv;
+ // There are for the LUP-decomposition of (I-\gamma*h*J)
+ std::array, N_eqs> L;
+ std::array, N_eqs> U;
+ std::array P;
+ //lu_sol will capture the sulution of (I-\gamma*h*J)* k = rhs (i.e. k = (I-\gamma*h*J)^{-1} rhs)
+ std::array lu_sol;
+ std::array, N_eqs> J;//this is here to hold values of the Jacobian
+
+
+
+
+
+
+ /*----------------------------------------------------------------------------------------------------*/
+ Ros(diffeq dydt, const std::array &init_cond, LD tmax,
+ LD initial_step_size=1e-5, LD minimum_step_size=1e-11, LD maximum_step_size=1e-3,int maximum_No_steps=1000000,
+ LD absolute_tolerance=1e-8,LD relative_tolerance=1e-8,LD beta=0.85,LD fac_max=3, LD fac_min=0.3);
+
+ ~Ros()=default;
+
+ /*-------------------it would be nice to have a way to define these sums more generaly-----------------*/
+ void next_step();
+ void LU();
+
+ void calc_k();
+ void calc_Jk();
+
+ void sum_ak(unsigned int stage); // calculate sum_j a_{ij}*k_j and passit to this->ak
+ void sum_gk(unsigned int stage); // calculate sum_j a_{ij}*k_j and passit to this->ak
+ void sum_bk();// calculate sum_i b_i*k_i and passit to this->bk
+ void sum_bstark();// calculate sum_i b^{\star}_i*k_i and passit to this->bk
+
+
+
+ void step_control();//adjust stepsize until error is acceptable
+ void solve();
+
+
+};
+
+
+
+#endif
diff --git a/src/NaBBODES/Rosenbrock/Ros_costructor.hpp b/src/NaBBODES/Rosenbrock/Ros_costructor.hpp
new file mode 100644
index 0000000..7ba3f62
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_costructor.hpp
@@ -0,0 +1,55 @@
+#ifndef Ros_constructor
+#define Ros_constructor
+#include "Ros_class.hpp"
+
+
+
+//The constructor. Remember that N has default value
+template
+Ros::Ros(diffeq dydt, const std::array &init_cond, LD tmax,
+ LD initial_step_size, LD minimum_step_size, LD maximum_step_size,int maximum_No_steps,
+ LD absolute_tolerance,LD relative_tolerance,LD beta,LD fac_max, LD fac_min){
+
+ // Initialize inputs
+ this->dydt=dydt;
+ this->tmax=tmax;
+ this->Jac=jacobian(dydt);
+ this->h=initial_step_size;
+ this->hmin=minimum_step_size;
+ this->hmax=maximum_step_size;
+ this->max_N=maximum_No_steps;
+ this->abs_tol=absolute_tolerance;
+ this->rel_tol=relative_tolerance;
+ this->beta=beta;
+ this->fac_max=fac_max;
+ this->fac_min=fac_min;
+
+ // ---------------------------------------------------------------------------------- //
+ //define yprev[N_eqs]. It is also good to initialize ynext.
+ (this->time).push_back(0);
+ for(unsigned int i = 0; i < N_eqs ;++i) {
+ this->yprev[i]=init_cond[i];
+ this->ynext[i]=init_cond[i];
+ (this->solution)[i].push_back( init_cond[i]);
+ (this->error)[i].push_back(0);
+ }
+
+ // ---------------------------------------------------------------------------------- //
+
+ //Initialize also k=0.
+ for(unsigned int i = 0; i < N_eqs ;++i){for(unsigned int j =0 ; jk[i][j] =0;}}
+
+
+ // calculate sums over gamma for all stages
+ for(unsigned int stage = 0; stage < RK_method::s; stage++){
+ this->sum_gamma[stage]=0;
+ for(unsigned int j =0 ; jsum_gamma[stage]+=RK_method::g[stage][j];}
+ }
+
+ //initialize tn
+ this->tn=0;
+ //initialize delta_acc
+ delta_acc=1.;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/NaBBODES/Rosenbrock/Ros_step_control-PI.hpp b/src/NaBBODES/Rosenbrock/Ros_step_control-PI.hpp
new file mode 100644
index 0000000..5cfae7b
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_step_control-PI.hpp
@@ -0,0 +1,62 @@
+#ifndef Ros_step_control
+#define Ros_step_control
+#include "Ros_class.hpp"
+
+#define max(a,b) (a <= b) ? b : a
+
+
+// Keep in mind that here delta_acc=Deltas.back(), while
+// delta_rej is the previous Delta (not the accepted one).
+
+/*-----------------------Begin: step_control---------------------------------*/
+template
+
+void Ros::step_control(){
+ LD Delta=0.;
+ LD _sc;
+ LD fac=beta;
+ // regulated_delta = (1-gam*h*J)^{-1}*abs_delta
+ std::array regulated_delta;
+ //PI step size cotrol from "Solving Ordinary Differential Equations II"
+ //We rescale the error by multiplying it with (1 + h \gamma J)^-1
+ dot( _inv, abs_delta , regulated_delta);
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ _sc=max(std::abs( ynext[eq] ), std::abs( yprev[eq] ));
+ _sc=abs_tol+rel_tol*_sc;
+ Delta+= (regulated_delta[eq]/_sc)*(regulated_delta[eq]/_sc);
+ }
+ Delta=std::sqrt(1./N_eqs*Delta);
+ if(Delta==0){Delta=abs_tol+rel_tol;}
+
+ // I use the step control from
+ // https://www.sciencedirect.com/science/article/pii/S147466701751767X
+ if(Delta<=1) {
+ if(delta_rej<=1){fac*=h/h_old; }
+ fac*=std::pow(Delta, -0.65/( static_cast(RK_method::p + 1)) );
+ fac*=std::pow( delta_acc/Delta, 0.3/ ( static_cast(RK_method::p + 1) ) );
+ // fac*=std::pow(delta_acc/Delta/Delta, 1/((LD) RK_method::p+1.) ) ;
+ h_stop=true ;
+ }else{
+ fac*=std::pow( Delta , -1./(static_cast(RK_method::p +1.) ) );
+ }
+
+ //this is an alternative. Not very good for some reason.
+ // fac*=h/h_old*std::pow(delta_acc/Delta/Delta, 1/((LD) RK_method::p+1.) ) ;
+
+ if(fac> fac_max){fac = fac_max;}
+ if(fac< fac_min){fac = fac_min;}
+ h= h*fac ;
+
+ if(Delta<=1){h_stop=true;}
+ if (h>hmax ){ h=hmax; h_stop=true;}
+ if (htmax ){ h=tmax-tn; }
+
+}
+/*-----------------------End: step_control---------------------------------*/
+#undef max
+#endif
diff --git a/src/NaBBODES/Rosenbrock/Ros_step_control-simple.hpp b/src/NaBBODES/Rosenbrock/Ros_step_control-simple.hpp
new file mode 100644
index 0000000..93a1db0
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_step_control-simple.hpp
@@ -0,0 +1,41 @@
+#ifndef Ros_step_control
+#define Ros_step_control
+#include "Ros_class.hpp"
+
+#define max(a,b) (a <= b) ? b : a
+
+
+/*-----------------------Begin: step_control---------------------------------*/
+template
+void Ros::step_control(){
+ LD Delta=0.;
+ LD _sc;
+ LD fac=beta;
+
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ _sc=max(std::abs( ynext[eq] ), std::abs( yprev[eq] ));
+ _sc=abs_tol+rel_tol*_sc;
+ Delta+= (abs_delta[eq]/_sc)*(abs_delta[eq]/_sc);
+ ;}
+
+ Delta=std::sqrt(1./N_eqs*Delta);
+ if(Delta<1) { h_stop=true ; }
+
+ //step size cotrol from "Solving Ordinary Differential Equations I"
+ fac*=std::pow( Delta , -1./( static_cast(RK_method::p + 1)));
+ if(fac> fac_max){fac = fac_max;}
+ if(fac< fac_min){fac = fac_min;}
+
+ h= h*fac ;
+
+ if (h>hmax ){ h=hmax; h_stop=true;}
+ if (htmax ){ h=tmax-tn;}
+}
+/*-----------------------End: step_control---------------------------------*/
+
+#undef max
+
+#endif
diff --git a/src/NaBBODES/Rosenbrock/Ros_steps.hpp b/src/NaBBODES/Rosenbrock/Ros_steps.hpp
new file mode 100644
index 0000000..a394323
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_steps.hpp
@@ -0,0 +1,75 @@
+#ifndef Ros_steps
+#define Ros_steps
+#include "Ros_class.hpp"
+
+
+
+/*---------------------------------------------------Begin: Get next step-------------------------------------------------------------------------------*/
+template
+void Ros::next_step(){
+ //set h_stop=false, to start looking for stepsize
+ h_stop=false;
+
+ h_old=h;//for the PI controller
+ delta_rej=delta_acc;//for the PI controller
+ //calculate the LU decomposition of (1-\gamma*h*J) and find its inverse before you enter the loop.
+ LU();
+ //calculate ynext and ynext_star until h_stop=true
+ while (true){
+ // calculate \vec{k}:
+ calc_k();
+
+ // now we can calulate \vec{y}_{n+1}
+ // for this we need sum_{i}^{s}b_{i}\vec{k}_i *h. That is, call sum_bk
+ sum_bk();
+
+ // having bk, we now have \vec{y}_{n+1} \vec{y}^{\star}_{n+1}.
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ ynext[eq] = yprev[eq] + bk[eq];
+ ynext_star[eq] = yprev[eq] + bstark[eq];
+ // calculate the error
+ abs_delta[eq]= ynext[eq] - ynext_star[eq] ;
+ }
+
+ // call step_control to see if the error is acceptable
+ step_control();
+
+ if(h_stop){break; }
+ }
+}
+/*---------------------------------------------------End: Get next step-------------------------------------------------------------------------------*/
+
+
+
+/*---------------------------------------------------Begin: solve-------------------------------------------------------------------------------*/
+
+template
+void Ros::solve(){
+ unsigned int current_step=0;
+ while (true){
+ //increase current_step
+ current_step++;
+ // check if it's done
+ if(tn>=tmax or current_step == max_N){break;}
+ // run next step
+ next_step();
+
+ // set previous y to last one
+ for (unsigned int eq = 0; eq < N_eqs; eq++){yprev[eq]=ynext[eq];}
+ // increase time
+ tn+=h;
+
+ // store everything
+ time.push_back(tn);
+ for (unsigned int eq = 0; eq < N_eqs; eq++){
+ solution[eq].push_back( ynext[eq] );
+ error[eq].push_back(ynext[eq] - ynext_star[eq]);
+ }
+ }
+}
+/*---------------------------------------------------End: solve-------------------------------------------------------------------------------*/
+
+
+
+
+#endif
diff --git a/src/NaBBODES/Rosenbrock/Ros_sums.hpp b/src/NaBBODES/Rosenbrock/Ros_sums.hpp
new file mode 100644
index 0000000..11f679e
--- /dev/null
+++ b/src/NaBBODES/Rosenbrock/Ros_sums.hpp
@@ -0,0 +1,52 @@
+#ifndef Ros_sums
+#define Ros_sums
+#include "Ros_class.hpp"
+
+/*-----------------------Begin: sum_ak---------------------------------*/
+template
+void Ros::sum_ak(unsigned int stage){
+ // this function stores sum_{j}^{stage-1}a_{stage,j}\vec{k}_j in ak, so we first need to make all elements zero,
+ // and then take the sum for each component
+ for (unsigned int eq = 0; eq
+void Ros::sum_gk(unsigned int stage){
+ // this function stores sum_{j}^{stage-1}g_{stage,j}\vec{k}_j in ak, so we first need to make all elements zero, and then take the sum for each component
+ for (unsigned int eq = 0; eq
+void Ros::sum_bk(){
+ // this function stores sum_{i}^{s}b_{i}\vec{k}_i in bk and sum_{i}^{s}b_{i}^{\star}\vec{k}_i in bstark
+ for (unsigned int eq = 0; eq
+#include
+#include