{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cbb3b7fb-23ba-4e29-b749-ad83ef6fcbd0",
   "metadata": {
    "tags": []
   },
   "source": [
    "# Automation\n",
    "\n",
    "This notebook demonstrates how to automate and display the results of multiple jobs while varying several computational parameters. In this case, we'll compute and display energy, C=O bond length, and C=O vibrational frequency of formaldehyde as a function of Theory and Basis Set.\n",
    "\n",
    "# Imports\n",
    "We'll start by importing our libraries:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b0e78a92-3243-4d1b-a677-0d0a82252024",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from webmo import WebMOREST\n",
    "from webmo.util import xyz_from_name\n",
    "from webmo.util import get_energy, get_bond_length, get_property\n",
    "import collections\n",
    "from tabulate import tabulate"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29d19269-0502-4d03-9703-8ad267f133a0",
   "metadata": {},
   "source": [
    "# User Setup\n",
    "\n",
    "Now we'll define all the variables the user can set and configure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "071a8807-30c0-4cb6-8920-9b15ac0fbc23",
   "metadata": {},
   "outputs": [],
   "source": [
    "## BOOKKEEPING VALUES\n",
    "# the URL of your WebMO instance\n",
    "URL = \"https://server.university.edu/~webmo/cgi-bin/webmo/rest.cgi\"\n",
    "\n",
    "# your WebMO username\n",
    "uname = \"smith\"\n",
    "\n",
    "## JOB VALUES\n",
    "# the molecule to run jobs on\n",
    "molecule = 'formaldehyde'\n",
    "\n",
    "# list of theories to try\n",
    "theories = [\"HF\", \"MP2\", \"B3LYP\"]\n",
    "\n",
    "# list of basis sets to try\n",
    "bases = [\"STO-3G\", \"3-21G\", \"6-31G(d)\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3cdf2d3-72e3-4d09-be9e-27f3ca41ef68",
   "metadata": {},
   "source": [
    "As well as start the REST session."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9c639d8d-8784-4a1b-9273-0c3850a9173e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter WebMO password for user smith: ········\n"
     ]
    }
   ],
   "source": [
    "rest = WebMOREST(URL, username=uname)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fca67ad3-65a0-4a54-9d3a-2cd35bd68d55",
   "metadata": {},
   "source": [
    "# Job Submission\n",
    "\n",
    "Now, we'll submit the jobs to WebMO. We start by getting the molecular geometry:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3a3027ae-d041-48cd-bd5e-bb107bd32e90",
   "metadata": {},
   "outputs": [],
   "source": [
    "geom = xyz_from_name(molecule)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f9536e1-a1a5-454f-a265-838ef281f844",
   "metadata": {},
   "source": [
    "Now we build our template dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "54337ae1-dc62-41f4-a12f-7afd79292e6a",
   "metadata": {},
   "outputs": [],
   "source": [
    "template = rest.get_templates('gaussian')['Optimize + Vib Freq'] # we're doing an OPT FREQ job in Gaussian\n",
    "# these values don't change\n",
    "variables = {\n",
    "    \"charge\":\"0\",\n",
    "    \"multiplicity\":\"1\",\n",
    "    \"geometry\":geom\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e44a8683-09b8-4bc3-b91d-f7e4dedf17d6",
   "metadata": {},
   "source": [
    "Now we'll submit the jobs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5bd49dac-62c9-4761-9769-190cc7e1fc93",
   "metadata": {},
   "outputs": [],
   "source": [
    "jids = collections.defaultdict(dict)\n",
    "\n",
    "for theory in theories:\n",
    "    variables['theory'] = theory\n",
    "\n",
    "    for basis in bases:\n",
    "        variables['basisSet'] = basis\n",
    "        variables['jobName'] = \"{}/{}\".format(theory,basis)\n",
    "\n",
    "        input_file = rest.generate_input(template, variables)\n",
    "        n = rest.submit_job(variables['jobName'],\n",
    "                            input_file,\n",
    "                            \"gaussian\")\n",
    "        jids[theory][basis] = n\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5e58504-75ae-4877-aad2-ce8f688dbe56",
   "metadata": {},
   "source": [
    "We can then wait for them to finish:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1b8b77af-ccde-4a57-abc5-5a4784d6c841",
   "metadata": {},
   "outputs": [],
   "source": [
    "for sub in jids:\n",
    "    for sub2 in jids[sub]:\n",
    "        rest.wait_for_job(jids[sub][sub2])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4bda343-2706-403d-9309-eee44de439df",
   "metadata": {},
   "source": [
    "# Results\n",
    "\n",
    "Finally, we'll get the results and display them in tables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "191c959a-34c6-4110-b8df-9ec7399c097c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimized Energy in Hartree:\n",
      "\n",
      "                     |          HF          |         MP2          |        B3LYP         |\n",
      "              STO-3G |     -112.354347      |     -112.475649      |     -112.957314      |\n",
      "               3-21G |     -113.221820      |     -113.439860      |     -113.861432      |\n",
      "            6-31G(d) |     -113.866331      |     -114.167748      |     -114.500473      |\n"
     ]
    }
   ],
   "source": [
    "# print misc. notes\n",
    "print(\"Optimized Energy in Hartree:\")\n",
    "print(\"\")\n",
    "\n",
    "# construct and print the table header\n",
    "headers = list(jids.keys())\n",
    "head = (\" \" * 20) + \" | \" + (' | '.join(['{:^20}']*len(headers)) + \" |\")\n",
    "print(head.format(*headers))\n",
    "\n",
    "# loop in alternate order to get right values\n",
    "for basis in bases:\n",
    "    print(\"{:>20} |\".format(basis), end=\"\")\n",
    "    for theory in theories:\n",
    "        print(\" {:^20.6f} |\".format(\n",
    "            get_energy(rest.get_job_results(jids[theory][basis])) # print energy\n",
    "        ), end=\"\")\n",
    "\n",
    "    print(\"\") # endline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "928eb011-0938-4425-b8c6-49b91c8f4e25",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C=O Bond Length in Angstroms:\n",
      "\n",
      "                     |          HF          |         MP2          |        B3LYP         |\n",
      "              STO-3G |       1.216738       |       1.262191       |       1.250670       |\n",
      "               3-21G |       1.206894       |       1.250061       |       1.227428       |\n",
      "            6-31G(d) |       1.184218       |       1.221158       |       1.206502       |\n"
     ]
    }
   ],
   "source": [
    "# print misc. notes\n",
    "print(\"C=O Bond Length in Angstroms:\")\n",
    "print(\"\")\n",
    "\n",
    "# construct and print the table header\n",
    "headers = list(jids.keys())\n",
    "head = (\" \" * 20) + \" | \" + (' | '.join(['{:^20}']*len(headers)) + \" |\")\n",
    "print(head.format(*headers))\n",
    "\n",
    "# loop in alternate order to get right values\n",
    "for basis in bases:\n",
    "    print(\"{:>20} |\".format(basis), end=\"\")\n",
    "    for theory in theories:\n",
    "        print(\" {:^20.6f} |\".format(\n",
    "            get_bond_length(rest.get_job_results(jids[theory][basis]),1,2) # print geometry\n",
    "        ), end=\"\")\n",
    "\n",
    "    print(\"\") # endline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "849c2d8e-bc32-428f-9fbb-d70544be9f41",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C=O Frequency in cm-1:\n",
      "\n",
      "                     |          HF          |         MP2          |        B3LYP         |\n",
      "              STO-3G |       2099.76        |       1799.57        |       1857.61        |\n",
      "               3-21G |       1915.71        |       1714.86        |       1758.78        |\n",
      "            6-31G(d) |       2028.55        |       1787.50        |       1849.74        |\n"
     ]
    }
   ],
   "source": [
    "# print misc. notes\n",
    "print(\"C=O Frequency in cm-1:\")\n",
    "print(\"\")\n",
    "\n",
    "# construct and print the table header\n",
    "headers = list(jids.keys())\n",
    "head = (\" \" * 20) + \" | \" + (' | '.join(['{:^20}']*len(headers)) + \" |\")\n",
    "print(head.format(*headers))\n",
    "\n",
    "# loop in alternate order to get right values\n",
    "for basis in bases:\n",
    "    print(\"{:>20} |\".format(basis), end=\"\")\n",
    "    for theory in theories:\n",
    "        print(\" {:^20.2f} |\".format(\n",
    "            get_property(rest.get_job_results(jids[theory][basis]),'vibrations')['frequencies'][4-1] # print frequency\n",
    "        ), end=\"\")\n",
    "\n",
    "    print(\"\") # endline"
   ]
  }
 ],
 "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.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
