{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Molecular dynamics with BubbleBox.mdbox\n", "\n", "Author Audun Skau Hansen ✉️ \n", "\n", "The Hylleraas Centre for Quantum Molecular Sciences, 2022\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "\n", "This tutorial gives a brief introduction to setting up and running simulations with BubbleBox in the Jupyter Notebook environment. Feel free to skip forward to the relevant information, just make sure you import the required modules." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Imports\n", "\n", "First, we have import the modules that we are going to use in the simulations:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import bubblebox as bb # The simulation toolkit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If any of the above import fails, please run:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install bubblebox" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "You will most likely also want to additionally import the following" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import numpy as np # numerical tools\n", "import matplotlib.pyplot as plt # the standard visualization toolkit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "...and that is all. Now your are now ready for the adventure." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
To set up a system we need to call a box and set up the initial parameters. The system can have a name, but we will just call it \"s\" for simplicity. In order to initialize it, we need to do the following:
\n", " \n", "\n", "```python3\n", " s = bb.mdbox(...) # the initial parameters are set up inside the parenthesis\n", "```\n", " \n", " The number of bubbles (n_bubbles
) is set ut as a positive integer and the size of the box (size
) is set up as a tuple using a (x,y,...)
format .The first number in the tuple is the size of the x axis in both positive and negative directions, and the second number is the size of the y axis in both positive and negative directions. The dimensionality is automatically determined from the number of size parameters. Most people prefer 3 or fewer dimensions.
Another parameter that is important for the system, is the initial velocity of the bubbles. The parameter vel
is set up as the maximum initial velocity a bubble can have, but their actual velocities are randomized between 0 and vel
. The default value for the vel
parameter is 0, so if the vel parameter is not written, it will be considered that the bubbles are at rest.
An example of setting up a box system with parameters is shown below:
\n", "\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "s = bb.mdbox(n_bubbles = 100, size = (10,10), vel = 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number of bubbles in this box is 100 and the dimensions are then set to a 10 x 10 box, going from -10 to 10 in both x and y directions. Their maximum initial velocity is set to 0, which means that the bubbles will start out with zero velocity.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After setting up the box, you'll likely want to look at what you created. This can be done with the .view()
method as follows:\n",
" \n",
"s.view()
\n",
"\n",
"Note that this command should always be at the end of the cell in the notebook, it returns a javascript canvas which is automatically added to the output region of the cell."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2bb93c89d4e442829e1e21c339885b45",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"MDView(box=[-35, -35], colors=[[0.690958858635848, 0.46257472231174124, 0.8967374453342962], [0.69095885863584…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Set up a monatomic, walled system\n",
"\n",
"# A 20 x 20 walled box\n",
"box_dims = (-35,-35)\n",
"\n",
"# Number of bubbles in box\n",
"# (Will be uniformly distributed inside box)\n",
"number_of_bubbles = 11**2\n",
"\n",
"\n",
"# Set up box\n",
"s = bb.box(n_bubbles = number_of_bubbles, box = box_dims, vel = 1) \n",
"\n",
"# Visualize box at current state\n",
"s.view()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
In Bubblebox, time may pass in at least three ways: advance
, evolve
and run
.\n",
" \n",
"Using finite-difference based time integration (explicit Euler or velocity verlet), the ```s.advance()``` method iterates one step in time. \n",
" \n",
"The ```s.evolve(1.0)``` method, on the other hand, makes several ```.advance()``` iterations in order to makes the time change with 1.0 unit. \n",
" \n",
"When you have a ```s.view()``` visible on screen, you may update the system using the ```s.update_view()``` method. For instance, the following two cells will create and animate the view:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Initial time : 0 s\n",
"Time after 1 dt: 0.001 s\n",
"Time after 1 s : 1.0010000000000006 s\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "96a660e0eaad4b3d9626d1b050c11218",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"MDView(box=[10, 10], colors=[[0.7922952578585167, 0.4840767287358104, 0.7109705457798324], [0.7922952578585167…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"## Time propagation methods\n",
"\n",
"#initializing a 20 x 20 box \n",
"s = bb.mdbox(n_bubbles = 64, size = (10,10),vel = 10)\n",
"\n",
"print(f\"Initial time : {s.t} s\")\n",
"\n",
"# Advance one single timestep\n",
"s.advance()\n",
"\n",
"print(f\"Time after 1 dt: {s.t} s\")\n",
"\n",
"# Advance for 1 second\n",
"s.evolve(1)\n",
"\n",
"print(f\"Time after 1 s : {s.t} s\")\n",
"\n",
"# Create a view of the system\n",
"s.view()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"# THIS LOOP RUNS FOREVER, PLEASE STOP IT USING THE STOP-BUTTON ABOVE\n",
"#while True:\n",
"# s.advance()\n",
"# s.update_view() "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, you may run a fixed number of iterations and simulatineously update the view using"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"s.run( 1000 ) #run 1000 advance steps and update view"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
masses
variable. The colors in Bubblebox are chosen automatically from the masses, so in order to make some nice mixed systems we can set these manually after initialization. Below, we set half the bubbles to a heavier mass:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "9b819a719eac48c482495c1b276fa83e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"MDView(box=[10, 10, 10], colors=[[0.4315227625339298, 0.6774390307459461, 0.07486468698226463], [0.42497975860…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Set up and run a diatomic system\n",
"\n",
"\n",
"# Set up box\n",
"s = bb.mdbox(n_bubbles = 1000, size = (10,10,10)) \n",
"\n",
"# Change mass of half the particles\n",
"s.masses = np.exp(-.03*np.sum(s.pos**2, axis = 0))\n",
"\n",
"\n",
"# view system\n",
"s.view() "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"active
variable is an 1D array with Boolean values, which tells us the status of the bubbles.\n",
" \n",
"An example of how to use it is shown below:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e152551fc11b4ec8ae372049316d3340",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"MDView(box=[-10, 10], colors=[[0.3456195046988272, 0.39979073385198804, 0.45859570844072395], [0.3456195046988…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Set up and run a diatomic system with fixed atoms at boundaries / irregular boundary conditions\n",
"\n",
"\n",
"\n",
"# Set up box\n",
"s = bb.mdbox(n_bubbles = 400, size = (-10,10)) \n",
"\n",
"# Change mass of half the bubbles\n",
"s.masses[int(s.n_bubbles/4):int(3*s.n_bubbles/4):] = 5\n",
"\n",
"# Assign more mass to the boundary, lock them in position\n",
"s.masses[:20] = 10\n",
"s.masses[-20:] = 10\n",
"\n",
"s.active[:20] = False\n",
"s.active[-20:] = False\n",
"\n",
"\n",
"\n",
"# Change timestep\n",
"s.dt = 0.005\n",
"\n",
"# Not much interesting will happen unless you add some tiny perturbation\n",
"s.vel_ = np.random.uniform(-.1, .1, system.vel_.shape)\n",
"\n",
"# view system\n",
"s.view() "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"