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 +#include"Interpolation.hpp" + +template +class CubicSpline: public Interpolation{ + using VecLD=std::vector; + using un_int=unsigned int; + + protected: + VecLD y2; + + public: + CubicSpline()=default; + + CubicSpline(VecLD *x,VecLD *y): Interpolation(x,y){ + y2.reserve(this->N); + for(un_int i=0; iN-1; ++i){y2.push_back(0);} + paramCalc(); + }; + + void paramCalc(); + + + + + LD operator()(LD x){ + /**/ + un_int i=this->bSearch(x); + un_int klo=i; + un_int khi=i+1; + + LD h=(*this->X)[khi]-(*this->X)[klo]; + + LD a=((*this->X)[khi]-x)/h; + LD b=(x-(*this->X)[klo])/h; + + LD y=a*(*this->Y)[klo]+b*(*this->Y)[khi]; + y+=(a*a*a-a)*y2[klo]*(h*h)/6.; + y+=(b*b*b-b)*y2[khi]*(h*h)/6.; + + return y; + } + + LD derivative_1(LD x){ + /*The first derivative of operator() obtained analytically.*/ + un_int i=this->bSearch(x); + + un_int klo=i; + un_int khi=i+1; + + LD h=(*this->X)[khi]-(*this->X)[klo]; + + LD a=((*this->X)[khi]-x)/h; + LD b=(x-(*this->X)[klo])/h; + + LD dydx=((*this->Y)[khi]-(*this->Y)[klo])/h; + dydx+=-(3*a*a-1)*y2[klo]*h/6.; + dydx+=(3*b*b-1)*y2[khi]*h/6.; + + return dydx; + } + + + LD derivative_2(LD x){ + /* + The second derivative of operator() obtained analytically. + */ + un_int i=this->bSearch(x); + LD a=((*this->X)[i+1]-x)/((*this->X)[i+1]-(*this->X)[i]); + return a*y2[i]+(1-a)*y2[i+1]; + } + + +}; + + + + + +template +void CubicSpline::paramCalc(){ + VecLD u(this->N-1,0); + LD sig,p; + + y2[0]=0; + y2[this->N-1]=0; + + for(un_int i=1; iN-1; ++i){ + sig=((*this->X)[i]-(*this->X)[i-1])/((*this->X)[i+1]-(*this->X)[i-1]); + p=sig*y2[i-1]+2; + y2[i]=(sig-1)/p; + u[i]=((*this->Y)[i+1]-(*this->Y)[i])/((*this->X)[i+1]-(*this->X)[i]) - ((*this->Y)[i]-(*this->Y)[i-1])/((*this->X)[i]-(*this->X)[i-1]); + u[i]=(6*u[i]/((*this->X)[i+1]-(*this->X)[i-1])-sig*u[i-1])/p; + } + + // we need k=N-2,N-1,...0 + for(int k=this->N-2; k>=0; --k){ + y2[k]=y2[k]*y2[k+1]+u[k]; + } + +} + + + +#endif \ No newline at end of file diff --git a/src/SimpleSplines/Interpolation.hpp b/src/SimpleSplines/Interpolation.hpp new file mode 100644 index 0000000..d4f144f --- /dev/null +++ b/src/SimpleSplines/Interpolation.hpp @@ -0,0 +1,10 @@ +#ifndef Interpolation_head +#define Interpolation_head + +#include"Interpolation_base.hpp" +#include"LinearSpline.hpp" +#include"CubicSpline.hpp" + + + +#endif \ No newline at end of file diff --git a/src/SimpleSplines/Interpolation_base.hpp b/src/SimpleSplines/Interpolation_base.hpp new file mode 100644 index 0000000..50ef36b --- /dev/null +++ b/src/SimpleSplines/Interpolation_base.hpp @@ -0,0 +1,95 @@ +#ifndef InterpolationBase_head +#define InterpolationBase_head + +#include +#include +#include + +template +class Interpolation{ + /* + Base class for spline interpolation + The class itself is the 0th order spline + */ + + using VecLD=std::vector; + using un_int=unsigned int; + + protected: + VecLD *X; + VecLD *Y; + un_int N; + + LD maxX,minX; + + public: + // constructor + Interpolation()=default; + + Interpolation(VecLD *x,VecLD *y){ + /*data to be used in interpolation*/ + try{//abort is data_x are in + this->X=x; + this->Y=y; + this->N=this->X->size(); + + for(un_int i=1; i=(*X)[i]){ throw "x must be in increasing order!!!";} + } + } catch(const char* errMsg){ + std::cout<maxX=this->X->operator[](this->N-1); + this->minX=this->X->operator[](0); + + } + + un_int bSearch(LD x){ + /* + This function takes a value (x) and finds which polynomial needs to be executed. + That is it returns i, for x between X[i] and X[i+1]. + */ + un_int L=0; + un_int R=N-1; + un_int m; + + // abort if the values are beyond the bounds + try{ + if(x>maxX){ throw "value beyond upper bound";} + if(x1){ + m=(un_int)(L+R)/2; + if(x>(*X)[m]) L=m; else R=m; + } + return L; + } + + + LD operator()(LD x){ + /* + 0th order spline + this is not good because the binary search is defined in such way that if x=X[N-1] + this function returns Y[N-2]. + */ + un_int i=bSearch(x); + return (*Y)[i]; + } + + virtual LD derivative_1(LD x){ + /*0^th order spline of the first derivative*/ + un_int i=bSearch(x); + return ( (*Y)[i]-(*Y)[i+1])/((*X)[i]-(*X)[i+1]); + } + virtual LD derivative_2(LD x)=0; + +}; + +#endif diff --git a/src/SimpleSplines/LICENSE b/src/SimpleSplines/LICENSE new file mode 100644 index 0000000..8a05c3f --- /dev/null +++ b/src/SimpleSplines/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Dimitrios 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/SimpleSplines/LinearSpline.hpp b/src/SimpleSplines/LinearSpline.hpp new file mode 100644 index 0000000..c381f05 --- /dev/null +++ b/src/SimpleSplines/LinearSpline.hpp @@ -0,0 +1,52 @@ +#ifndef LinearSpline_head +#define LinearSpline_head + +#include +#include +#include"Interpolation.hpp" + + +template +class LinearSpline: public Interpolation{ + using VecLD=std::vector; + using un_int=unsigned int; + + + public: + LinearSpline()=default; + + LinearSpline(VecLD *x,VecLD *y): Interpolation(x,y){}; + + LD operator()(LD x){ + /* + 1st order spline + */ + un_int i=this->bSearch(x); + LD a=((*this->X)[i+1]-x)/((*this->X)[i+1]-(*this->X)[i]); + return a*(*this->Y)[i]+(1-a)*(*this->Y)[i+1]; + } + + virtual LD derivative_1(LD x){ + /* + 1st order spline of the first derivative. + It is better than taking the derivative of operator() + */ + un_int i=this->bSearch(x); + LD xi=(*this->X)[i],yi=(*this->Y)[i]; + LD xj=(*this->X)[i+1],yj=(*this->Y)[i+1]; + + if (i==this->N-2) {return (yi-yj)/(xi-xj);} + + LD a=(xj-x)/(xj-xi); + LD dydx0=(yi-yj)/(xi-xj); + LD dydx1=(yj-(*this->Y)[i+2])/(xj-(*this->X)[i+2]); + + return a*dydx0+(1-a)*dydx1; + } + + + +}; + + +#endif \ No newline at end of file diff --git a/src/SimpleSplines/spline_example.cpp b/src/SimpleSplines/spline_example.cpp new file mode 100644 index 0000000..5063ed8 --- /dev/null +++ b/src/SimpleSplines/spline_example.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + + +#include"Interpolation.hpp" + +using std::cout; +using std::endl; +using std::vector; +using std::sin; +using std::cos; +using std::exp; + + +template +void linspace(LD min, LD max, unsigned int length, vector *X){ + X->reserve(length); + for(unsigned int i = 0; ipush_back( min + i*(max-min)/( length-1 ) ); + } +} + + + +template +void map(vector *X , LD(* func)(LD), vector *Y){ + unsigned int length=X->size(); + Y->reserve(length); + + for(unsigned int i = 0; i < length ; ++i){ + Y->push_back (func((*X)[i])) ; + } +} + + +#ifndef LONG +#define LONG +#endif + +#define LD LONG double + +int main(){ + vectorx,x_int; + vectory,yp,ypp; + unsigned int N=50; + + + linspace(-M_PI,M_PI,N,&x); + map(&x,sin,&y); + map(&x,cos,&yp); + for (unsigned int i = 0; i < x.size(); i++){ypp.push_back(-y[i]);} + + + + Interpolation intrp0(&x,&y); + LinearSpline intrp1(&x,&y); + CubicSpline intrp3(&x,&y); + + + #if 1 + for (unsigned int i = 0; i < x.size(); i++){ + cout<(-M_PI,M_PI,N*30,&x_int); + for (unsigned int i = 0; i < x_int.size(); i++){ + cout<