├── MD.ipynb └── README.md /MD.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "from itertools import product\n", 13 | "rho = .88 # density of Argon in natural units\n", 14 | "dt = 0.004 # time step size\n", 15 | "T_0 = 1 # temperature\n", 16 | "N_cell = 3 # number of unitcells in one direction \n", 17 | "N = 4 * N_cell ** 3 # the total number of particles in the system\n", 18 | "L_box = (N / rho) ** (1 / 3) # length of the whole box\n", 19 | "L_cell = L_box / N_cell # length of a unitcell\n", 20 | "F = np.zeros((N, N, 3)) # matrix that contains all forces\n", 21 | "ind = np.triu_indices(N, k=1) # indices of upper triangular matrix\n", 22 | "bins = 30" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [], 32 | "source": [ 33 | "def IC_pos(N_cell, L_cell):\n", 34 | " pos = [[[x, y, z], [x, 0.5 + y, 0.5 + z], [0.5 + x, y, 0.5 + z], [0.5 + x, 0.5 + y, z]] \n", 35 | " for x, y, z in product(range(N_cell), range(N_cell), range(N_cell))]\n", 36 | " pos = np.array(pos).reshape((-1, 3))\n", 37 | " return pos * L_cell\n", 38 | "\n", 39 | "\n", 40 | "def IC_vel(N):\n", 41 | " vel = np.random.randn(N, 3)\n", 42 | " vel -= np.average(vel, axis=0)\n", 43 | " return vel \n", 44 | "\n", 45 | "\n", 46 | "def find_force(pos, L_box=L_box):\n", 47 | " r_vec = pos[ind[0]] - pos[ind[1]]\n", 48 | " r_vec = r_vec - np.rint(r_vec / L_box) * L_box\n", 49 | " r_sq = np.sum(r_vec**2, axis=1)\n", 50 | " F_vec = -(48 / r_sq ** 7 - 24 / r_sq ** 4)[:, None] * r_vec\n", 51 | " F[ind[0], ind[1]] = F_vec\n", 52 | " pot = np.sum(4 / r_sq ** 6 - 4 / r_sq ** 3)\n", 53 | " P = np.sum(F_vec * r_vec)\n", 54 | " hist = np.histogram(r_sq, bins=bins, range=(0, L_box / 2))[0]\n", 55 | " return np.sum(F, axis=0) - np.sum(F, axis=1), pot, P, hist\n", 56 | "\n", 57 | "\n", 58 | "def time_step(pos, vel, F):\n", 59 | " vel += 0.5 * F * dt\n", 60 | " pos = np.mod(pos + vel * dt, L_box)\n", 61 | " F, pot, P, hist = find_force(pos)\n", 62 | " \n", 63 | " vel += 0.5 * F * dt\n", 64 | " kin = 0.5 * np.sum(vel**2)\n", 65 | " return pos, vel, F, pot, kin, P, hist" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 7, 71 | "metadata": { 72 | "collapsed": false 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "def simulate():\n", 77 | " kins, pots, Ps, hists = [], [], [], []\n", 78 | " pos = IC_pos(N_cell, L_cell)\n", 79 | " vel = IC_vel(N)\n", 80 | " F = find_force(pos)[0]\n", 81 | " for t in range(10000):\n", 82 | " pos, vel, F, pot, kin, P, hist = time_step(pos, vel, F)\n", 83 | " if t > 1000:\n", 84 | " kins.append(kin)\n", 85 | " pots.append(pot)\n", 86 | " Ps.append(P)\n", 87 | " hists.append(hist)\n", 88 | " else:\n", 89 | " vel *= np.sqrt(N * 3 * T_0 / (2 * kin))\n", 90 | " return np.array(kins), np.array(pots), np.array(Ps), np.mean(hists, axis=0)\n", 91 | "\n", 92 | "kins, pots, Ps, hist = simulate()\n", 93 | "\n", 94 | "T = np.mean(kins * 2 / (3 * N))\n", 95 | "P = 1 - np.mean(Ps) / (3 * N * T) - 16 * np.pi * rho / (3 * T * L_box**3)" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 8, 101 | "metadata": { 102 | "collapsed": false 103 | }, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/html": [ 108 | "\n", 109 | "\n", 110 | "\n", 564 | "\n", 565 | "\n", 566 | "\n", 567 | "\n", 631 | "\n", 632 | "\n", 633 | "
\n", 634 | "\n", 636 | "\n", 637 | "HoloViewsJS, MatplotlibJS successfully loaded in this cell.\n", 638 | "
\n" 639 | ], 640 | "text/plain": [ 641 | "" 642 | ] 643 | }, 644 | "metadata": {}, 645 | "output_type": "display_data" 646 | }, 647 | { 648 | "name": "stdout", 649 | "output_type": "stream", 650 | "text": [ 651 | "Final temperature is 1.038\n", 652 | "Final Pressure is 3.493\n" 653 | ] 654 | }, 655 | { 656 | "data": { 657 | "text/html": [ 658 | "" 659 | ], 660 | "text/plain": [ 661 | ":Overlay\n", 662 | " .Curve.Kinetic_energy :Curve [x] ($E$)\n", 663 | " .Curve.Potential_energy :Curve [x] ($E$)\n", 664 | " .Curve.Total_energy :Curve [x] ($E$)" 665 | ] 666 | }, 667 | "execution_count": 8, 668 | "metadata": {}, 669 | "output_type": "execute_result" 670 | } 671 | ], 672 | "source": [ 673 | "import holoviews as hv\n", 674 | "hv.notebook_extension('matplotlib')\n", 675 | "\n", 676 | "print(\"Final temperature is {:.4}\".format(T))\n", 677 | "print(\"Final Pressure is {:.4}\".format(P))\n", 678 | " \n", 679 | "(hv.Curve(kins, label='Kinetic energy', vdims=[r'$E$']) * \n", 680 | " hv.Curve(pots, label='Potential energy', vdims=[r'$E$']) * \n", 681 | " hv.Curve(pots + kins, label='Total energy', vdims=[r'$E$']))" 682 | ] 683 | }, 684 | { 685 | "cell_type": "code", 686 | "execution_count": 9, 687 | "metadata": { 688 | "collapsed": false 689 | }, 690 | "outputs": [ 691 | { 692 | "data": { 693 | "text/html": [ 694 | "" 695 | ], 696 | "text/plain": [ 697 | "b':Path [$r$,$g(r)$]'" 698 | ] 699 | }, 700 | "execution_count": 9, 701 | "metadata": {}, 702 | "output_type": "execute_result" 703 | } 704 | ], 705 | "source": [ 706 | "%%opts Path [aspect='square']\n", 707 | "r = np.linspace(0, L_box / 2, bins)\n", 708 | "pair_correlation = hist / (4 * np.pi * rho * r)\n", 709 | "hv.Path((r, pair_correlation), kdims=[r'$r$', r'$g(r)$'])" 710 | ] 711 | }, 712 | { 713 | "cell_type": "code", 714 | "execution_count": 6, 715 | "metadata": { 716 | "collapsed": false 717 | }, 718 | "outputs": [ 719 | { 720 | "name": "stdout", 721 | "output_type": "stream", 722 | "text": [ 723 | "1 loop, best of 3: 362 ms per loop\n" 724 | ] 725 | } 726 | ], 727 | "source": [ 728 | "%timeit simulate()" 729 | ] 730 | } 731 | ], 732 | "metadata": { 733 | "kernelspec": { 734 | "display_name": "Python 3", 735 | "language": "python3", 736 | "name": "python3" 737 | }, 738 | "language_info": { 739 | "codemirror_mode": { 740 | "name": "ipython", 741 | "version": 3 742 | }, 743 | "file_extension": ".py", 744 | "mimetype": "text/x-python", 745 | "name": "python", 746 | "nbconvert_exporter": "python", 747 | "pygments_lexer": "ipython3", 748 | "version": "3.5.1" 749 | } 750 | }, 751 | "nbformat": 4, 752 | "nbformat_minor": 0 753 | } 754 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MD-python 2 | Molecular dynamics simulation of an Argon gas as example for the computational physics I teach. 3 | 4 | Shows the beauty of Python, compare with this `FORTRAN` [code](https://github.com/basnijholt/molecular-dynamics-FORTRAN) I wrote when I took this class myself. 5 | --------------------------------------------------------------------------------