diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..52e4b0d --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 4896b3dcb84feb831e010853d427cb70 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/_images/09fe80c6ba25ad729eef61b8d00eff57e6462b1be2e6ed7dff34d39e689c9bf2.png b/_images/09fe80c6ba25ad729eef61b8d00eff57e6462b1be2e6ed7dff34d39e689c9bf2.png new file mode 100644 index 0000000..d1726fc Binary files /dev/null and b/_images/09fe80c6ba25ad729eef61b8d00eff57e6462b1be2e6ed7dff34d39e689c9bf2.png differ diff --git a/_images/dc5abca5e1bf9d2bfe01fb6245c5a5eae3c35a54e9dc2423733f12d55ac4a0ab.png b/_images/dc5abca5e1bf9d2bfe01fb6245c5a5eae3c35a54e9dc2423733f12d55ac4a0ab.png new file mode 100644 index 0000000..0e38be4 Binary files /dev/null and b/_images/dc5abca5e1bf9d2bfe01fb6245c5a5eae3c35a54e9dc2423733f12d55ac4a0ab.png differ diff --git a/_sources/index.rst b/_sources/index.rst new file mode 100644 index 0000000..226d759 --- /dev/null +++ b/_sources/index.rst @@ -0,0 +1,29 @@ +VAMPyR coven +===================== + +This is a collection of notebooks for VAMPyR, the Very Accurate Multiresolution Python Routines library. The repository holds Jupyter notebooks that demonstrate the use of VAMPyR for various scientific computations and simulations. + +The setup notebook provides instructions for installing and configuring the VAMPyR library and its dependencies, ensuring the environment is prepared for all subsequent simulations. + +.. toctree:: + :hidden: + :maxdepth: 1 + + setup + +The demos include: + +- The beryllium atom notebook, where users can learn about quantum mechanical modeling of the beryllium atom, including setting up the atomic structure, calculating energy levels, and visualizing electron orbitals using VAMPyR. +- The harmonic oscillator evolution notebook guides users through the simulation of the time evolution of a quantum harmonic oscillator, demonstrating the use of VAMPyR to solve the Schrödinger equation and analyze system dynamics. +- The PCMSolvent notebook focuses on the application of the Polarizable Continuum Model (PCM) for simulating solvent effects. It shows how VAMPyR can be used to model the influence of a solvent as a polarizable continuum on a solute molecule. + +These notebooks can be run directly in the browser for convenience, but for those who prefer or require local execution, it is also possible to download the repository and run the notebooks on one's own machine. + +.. toctree:: + :hidden: + :maxdepth: 1 + :caption: Demos + + notebooks/beryllium_atom + notebooks/harmonic_oscillator_evolution + notebooks/PCMSolvent diff --git a/_sources/notebooks/H-atom-4c.ipynb b/_sources/notebooks/H-atom-4c.ipynb new file mode 100644 index 0000000..8f9822b --- /dev/null +++ b/_sources/notebooks/H-atom-4c.ipynb @@ -0,0 +1,299 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "90e862bb-783a-4f97-a227-8f6e0b4012b8", + "metadata": {}, + "source": [ + "# The Dirac equation for the Hydrogen atom\n", + "\n", + "In this notebook we will illustrate how one can solve the Dirac equation for a Hydrogen atom using the Multiwavelet framework provided by VAMPyR\n", + "\n", + "The Dirac equation can be coincisely written as follows:\n", + "\n", + "\\begin{equation}\n", + "(\\beta m c^2+ c \\boldsymbol{\\alpha} \\cdot \\mathbf{p} + V) \\phi = \\epsilon \\phi \n", + "\\end{equation}\n", + "\n", + "where $\\phi = (\\phi^{L\\alpha}, \\phi^{L\\beta}, \\phi^{S\\alpha}, \\phi^{S\\beta})^t$ represents a 4-component spinor, $\\boldsymbol{\\alpha} = \n", + "\\begin{pmatrix}\n", + "0_2 & \\boldsymbol{\\sigma} \\\\\n", + "\\boldsymbol{\\sigma} & 0_2 & \n", + "\\end{pmatrix}\n", + "$ and\n", + "$\\beta = \n", + "\\begin{pmatrix}\n", + "1_2 & 0_2 \\\\\n", + "0_2 & -1_2\n", + "\\end{pmatrix}\n", + "$ are the 4x4 Dirac matrices, $\\boldsymbol{\\sigma}$ is a cartesian vector collecting the three 2x2 Pauli matrices, $\\mathbf{p}$ is the momentum operator, $c$ is the speed of light, $m$ is the electron mass and $V$ is the nuclear potential.\n", + "\n", + "As for the non-relativistic case, the equation is first rewritten in its integral formulation:\n", + "$$\\phi = \\frac{1}{2mc^2}(\\beta m c^2+ c \\boldsymbol{\\alpha} \\cdot \\mathbf{p} + \\epsilon) \\left[ G_\\mu \\star (V \\psi) \\right]$$\n", + "\n", + "where $G_\\mu(x) = \\frac{e^{-\\mu |x|}}{4 \\pi |x|}$ is the Helmholtz Green's kernel and $\\mu = \\sqrt{\\frac{m^2c^4-\\epsilon}{mc^2}}$. An initial guess can be obtained by taking a Slater orbital or a Gaussian function for the $\\psi^{L\\alpha}$ component and then applying the restricted kinetic balance:\n", + "\n", + "$$\n", + "\\begin{pmatrix}\n", + "\\phi^{S\\alpha} \\\\\n", + "\\phi^{S\\beta}\n", + "\\end{pmatrix}\n", + "= \\frac{1}{2c}\\boldsymbol{\\sigma} \\cdot \\mathbf{p} \n", + "\\begin{pmatrix}\n", + "\\phi^{L\\alpha} \\\\\n", + "0\n", + "\\end{pmatrix}\n", + "$$\n", + "The guess obtained is then plugged into the integral form of the Dirac equation, which can then be iterated until convergence" + ] + }, + { + "cell_type": "markdown", + "id": "54c75006-0358-42c5-9075-37a5b8a909ba", + "metadata": {}, + "source": [ + "We start by loading the relevant packages: the 3d version of `vampyr`, `numpy`, the `complex_function` class which deals with complex funtions and the `orbital` class which deals with 4-component spinors. Each complex function is handled as a pair of `function_tree`s and each spinor is handled as a 4c vector of complex functions. The `nuclear_potential` package is self-explanatory" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "37e0e6b2-886e-4415-8612-d2a652f24c4f", + "metadata": {}, + "outputs": [], + "source": [ + "from vampyr import vampyr3d as vp\n", + "from orbital4c import orbital as orb\n", + "from orbital4c import nuclear_potential as nucpot\n", + "from orbital4c import complex_fcn as cf\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "7fbe4360-9936-47d4-bb6f-d51bb3b34b69", + "metadata": {}, + "source": [ + "As a reference, the exact Dirac energy for the ground state Hydrogen atom is computed in the function below." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0ef3d827-810b-4411-8ba3-bd63271033e4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exact Energy -0.5000066565989982\n" + ] + } + ], + "source": [ + "def analytic_1s(light_speed, n, k, Z):\n", + " alpha = 1/light_speed\n", + " gamma = orb.compute_gamma(k,Z,alpha)\n", + " tmp1 = n - np.abs(k) + gamma\n", + " tmp2 = Z * alpha / tmp1\n", + " tmp3 = 1 + tmp2**2\n", + " return light_speed**2 / np.sqrt(tmp3)\n", + "\n", + "light_speed = 137.03599913900001\n", + "alpha = 1/light_speed\n", + "k = -1\n", + "l = 0\n", + "n = 1\n", + "m = 0.5\n", + "Z = 1\n", + "atom = \"H\"\n", + "\n", + "energy_1s = analytic_1s(light_speed, n, k, Z)\n", + "print('Exact Energy',energy_1s - light_speed**2, flush = True)" + ] + }, + { + "cell_type": "markdown", + "id": "6277d776-2236-496a-bdd5-41929d11ac3d", + "metadata": {}, + "source": [ + "The `MultiResolutionAnalysis` object defining the simulation box is constructed and passed to the classes for complex functions and spinors" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "5ac41574-6f43-411d-841f-f8fdf0749b66", + "metadata": {}, + "outputs": [], + "source": [ + "mra = vp.MultiResolutionAnalysis(box=[-30,30], order=6)\n", + "prec = 1.0e-4\n", + "origin = [0.1, 0.2, 0.3] # origin moved to avoid placing the nuclar charge on a node\n", + "\n", + "orb.orbital4c.light_speed = light_speed\n", + "orb.orbital4c.mra = mra\n", + "cf.complex_fcn.mra = mra" + ] + }, + { + "cell_type": "markdown", + "id": "d5abdbe4-ba5b-49d3-ae7e-febab5ced4fe", + "metadata": {}, + "source": [ + "We construct a starting guess by taking a simple Gaussian function and initialize the real part of the $\\phi^{L\\alpha}$ component of the spinor with it. Thereafter the restricted kinetic balance is employed. This is implemented in the `init_small_components` method of the `orbital` class" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "95826623-b759-4318-afc5-e0c225cb5f1d", + "metadata": {}, + "outputs": [], + "source": [ + "a_coeff = 3.0\n", + "b_coeff = np.sqrt(a_coeff/np.pi)**3\n", + "gauss = vp.GaussFunc(b_coeff, a_coeff, origin)\n", + "gauss_tree = vp.FunctionTree(mra)\n", + "vp.advanced.build_grid(out=gauss_tree, inp=gauss)\n", + "vp.advanced.project(prec=prec, out=gauss_tree, inp=gauss)\n", + "gauss_tree.normalize()\n", + "\n", + "spinor_H = orb.orbital4c()\n", + "La_comp = cf.complex_fcn()\n", + "La_comp.copy_fcns(real = gauss_tree)\n", + "spinor_H.copy_components(La = La_comp)\n", + "spinor_H.init_small_components(prec/10)\n", + "spinor_H.normalize()" + ] + }, + { + "cell_type": "markdown", + "id": "f6a40ddd-7933-46ee-8128-96caf89f3682", + "metadata": {}, + "source": [ + "The nuclear potential is defined and projected onto the `V_tree`" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "4f0cda6f-217c-4941-8ce5-fa52576c2d98", + "metadata": {}, + "outputs": [], + "source": [ + "Peps = vp.ScalingProjector(mra, prec)\n", + "f = lambda x: nucpot.coulomb_HFYGB(x, origin, Z, prec)\n", + "V_tree = Peps(f)\n", + "\n", + "default_der = 'BS'" + ] + }, + { + "cell_type": "markdown", + "id": "1678bc97-d85d-4a48-9aea-13901631534d", + "metadata": {}, + "source": [ + "The orbital is optimized by iterating the integral version of the Dirac equation as follows:\n", + "1. Application of the Dirac Hamiltonian $f^n = \\hat{h}_D \\phi^n = (\\beta m c^2+ c \\boldsymbol{\\alpha} \\cdot \\mathbf{p}) \\phi^n$\n", + "2. Application of the potnetial operator $g^n = \\hat{V} \\phi^n$\n", + "3. Sum $h^n = f^n + g^n$\n", + "4. Expectation value of the energy $\\left\\langle \\phi^n | h^n \\right\\rangle$\n", + "5. Calculation of the Helmholtz parameter $\\mu$\n", + "6. Convolution with the Helmholtz kernel $t^n = G_\\mu \\star g^n$\n", + "7. application of the shifted Dirac Hamiltonian $\\tilde{\\phi}^{n+1} = (\\hat{h}_D + \\epsilon) t^n$\n", + "8. normalization of the new iterate\n", + "9. calculation of the change in the orbital $\\delta \\phi^n = \\phi^{n+1}-\\phi^n$\n", + "\n", + "Once the orbital error is below the requested threshold the iteration is interrupted and the final energy is computed." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "40a443b6-33f4-4771-8b06-ccd12c9da35d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Energy -0.14180720307558659\n", + "Error 0.3648353655184581\n", + "Energy -0.49611934473068686\n", + "Error 0.0024839139737050653\n", + "Energy -0.4997319277244969\n", + "Error 0.00023304055836475225\n", + "Energy -0.49998214000152075\n", + "Error 2.3987883028320866e-05\n", + "Final Energy -0.5000042447172746\n", + "Exact Energy -0.5000066565989982\n", + "Difference -2.411881723674014e-06\n" + ] + } + ], + "source": [ + "orbital_error = 1\n", + "while orbital_error > prec:\n", + " # 1. Application of the Dirac Hamiltonian\n", + " hd_psi = orb.apply_dirac_hamiltonian(spinor_H, prec, der = default_der)\n", + " # 2. Application of the potnetial operator\n", + " v_psi = orb.apply_potential(-1.0, V_tree, spinor_H, prec)\n", + " # 3. Sum\n", + " add_psi = hd_psi + v_psi\n", + " # 4. Expectation value of the energy\n", + " energy = (spinor_H.dot(add_psi)).real\n", + " print('Energy',energy-light_speed**2)\n", + " # 5. Calculation of the Helmholtz parameter\n", + " mu = orb.calc_dirac_mu(energy, light_speed)\n", + " # 6. Convolution with the Helmholtz kernel\n", + " tmp = orb.apply_helmholtz(v_psi, mu, prec)\n", + " tmp.crop(prec/10)\n", + " # 7. application of the shifted Dirac Hamiltonian\n", + " new_orbital = orb.apply_dirac_hamiltonian(tmp, prec, energy, der = default_der) \n", + " new_orbital.crop(prec/10)\n", + " # 8. normalization of the new iterate\n", + " new_orbital.normalize()\n", + " delta_psi = new_orbital - spinor_H\n", + " # 9. calculation of the change in the orbital\n", + " orbital_error = (delta_psi.dot(delta_psi)).real\n", + " print('Error',orbital_error, flush = True)\n", + " spinor_H = new_orbital\n", + "\n", + "# Computing the final energy\n", + "hd_psi = orb.apply_dirac_hamiltonian(spinor_H, prec, der = default_der)\n", + "v_psi = orb.apply_potential(-1.0, V_tree, spinor_H, prec)\n", + "add_psi = hd_psi + v_psi\n", + "energy = (spinor_H.dot(add_psi)).real\n", + "print('Final Energy',energy - light_speed**2)\n", + "\n", + "energy_1s = analytic_1s(light_speed, n, k, Z)\n", + "\n", + "print('Exact Energy',energy_1s - light_speed**2)\n", + "print('Difference',energy_1s - energy)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/notebooks/PCMSolvent.ipynb b/_sources/notebooks/PCMSolvent.ipynb new file mode 100644 index 0000000..adadf40 --- /dev/null +++ b/_sources/notebooks/PCMSolvent.ipynb @@ -0,0 +1,567 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "ea98d79d", + "metadata": { + "tags": [ + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "\"\"\"Polarizable continuum model (PCM).\"\"\"\n", + "\n", + "__author__ = \"Gabriel Gerez\"\n", + "__credit__ = [\"Gabriel Gerez\"]\n", + "\n", + "__date__ = \"2023-08-28\"" + ] + }, + { + "cell_type": "markdown", + "id": "2178d62d", + "metadata": { + "tags": [ + "remove_cell" + ] + }, + "source": [ + "
Shift + Enter\n", + "
Shift + Enter\n", + "
Short
+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 0000000..2ea7ff3 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = `` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = `` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 0000000..dbe1aaa --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..527b876 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..1e67fc8 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/images/logo_binder.svg b/_static/images/logo_binder.svg new file mode 100644 index 0000000..45fecf7 --- /dev/null +++ b/_static/images/logo_binder.svg @@ -0,0 +1,19 @@ + + + diff --git a/_static/images/logo_colab.png b/_static/images/logo_colab.png new file mode 100644 index 0000000..b7560ec Binary files /dev/null and b/_static/images/logo_colab.png differ diff --git a/_static/images/logo_deepnote.svg b/_static/images/logo_deepnote.svg new file mode 100644 index 0000000..fa77ebf --- /dev/null +++ b/_static/images/logo_deepnote.svg @@ -0,0 +1 @@ + diff --git a/_static/images/logo_jupyterhub.svg b/_static/images/logo_jupyterhub.svg new file mode 100644 index 0000000..60cfe9f --- /dev/null +++ b/_static/images/logo_jupyterhub.svg @@ -0,0 +1 @@ + diff --git a/_static/jquery-3.6.0.js b/_static/jquery-3.6.0.js new file mode 100644 index 0000000..fc6c299 --- /dev/null +++ b/_static/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML