{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# OPICS Multiprocessing\n", "\n", "OPICS support multiprocessing for faster simulations when working with large circuits. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " ____ ____ _______________\n", " / __ \\/ __ \\/ _/ ____/ ___/\n", " / / / / /_/ // // / \\__ \\\n", "/ /_/ / ____// // /___ ___/ /\n", "\\____/_/ /___/\\____//____/\n", "\n", "OPICS version 0.3.1\n" ] } ], "source": [ "import multiprocessing as mp\n", "import opics as op\n", "import numpy as np\n", "import pandas as pd\n", "import time\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Enabling multiprocessing\n", "\n", "### Option 1: Using `mp_config`\n", "\n", "OPICS multiprocessing can be enabled using the `mp_config` argument in `opics.Network` module." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OPICS multiprocessing is enabled.\n" ] } ], "source": [ "circuit = op.Network(network_id=\"MRR_arr\", mp_config={\"enabled\": True, \"proc_count\": 0, \"close_pool\": True})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Option 2: Using `enable_mp`\n", "OPICS multiprocessing can also be enabled by calling the `enable_mp` function in `opics.Network` module." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OPICS multiprocessing is enabled.\n" ] } ], "source": [ "circuit = op.Network(network_id = \"MRR_arr\")\n", "circuit.enable_mp( process_count = 0, \n", " close_pool = True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Disable multiprocessing\n", "\n", "OPICS multiprocessing can be disabled by calling the `disable_mp` function." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OPICS multiprocessing is disabled.\n" ] } ], "source": [ "circuit.disable_mp()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example: Multiple ring resonators coupled to a waveguide\n", "\n", "In order to see how multiprocessing can help speed-up simulations, let's create a circuit with `n` number of ring resonators coupled to a waveguide. \n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Without multiprocessing\n", "\n", "We will be using `bulk_add_component` to add multiple components to the network." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "components = op.libraries.ebeam\n", "from opics.network import bulk_add_component" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "simulation finished in 18.5154269 s\n" ] } ], "source": [ "timer_start = time.perf_counter()\n", "\n", "circuit = op.Network()\n", "\n", "n_rings = 1500\n", "\n", "_components_data = []\n", "\n", "for count in range(n_rings):\n", " _components_data.append(\n", " {\"component\": components.DC_halfring,\n", " \"params\": {\"f\": circuit.f},\n", " \"component_id\": f\"dc_{count}\"})\n", "\n", " _components_data.append(\n", " {\"component\": components.Waveguide,\n", " \"params\": {\"f\": circuit.f, \"length\": np.pi * 5e-6},\n", " \"component_id\": f\"wg_{count}\"})\n", "\n", "bulk_add_component(circuit, _components_data)\n", "\n", "circuit.add_component(components.GC, component_id=\"input\")\n", "circuit.add_component(components.GC, component_id=\"output\")\n", "\n", "# bulk connect\n", "prev_comp = \"\"\n", "for count in range(n_rings):\n", " if count == 0:\n", " circuit.connect(\"input\", 1, f\"dc_{count}\", 0)\n", " circuit.connect(f\"dc_{count}\", 1, f\"wg_{count}\", 0)\n", " circuit.connect(f\"wg_{count}\", 1, f\"dc_{count}\", 3)\n", " prev_comp = \"dc_0\"\n", "\n", " elif count >= 1:\n", " circuit.connect(prev_comp, 2, f\"dc_{count}\", 0)\n", " circuit.connect(f\"dc_{count}\", 1, f\"wg_{count}\", 0)\n", " circuit.connect(f\"wg_{count}\", 1, f\"dc_{count}\", 3)\n", " prev_comp = f\"dc_{count}\"\n", "\n", "circuit.connect(prev_comp, 2, \"output\", 1)\n", "\n", "circuit.simulate_network()\n", "timer_stop = time.perf_counter()\n", "sim_time = timer_stop - timer_start\n", "print(f\"simulation finished in {sim_time} s\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With multiprocessing enabled" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OPICS multiprocessing is enabled.\n", "simulation finished in 13.326252699999998 s\n" ] } ], "source": [ "timer_start = time.perf_counter()\n", "\n", "circuit = op.Network()\n", "\n", "circuit.enable_mp()\n", "\n", "n_rings = 1500\n", "\n", "_components_data = []\n", "\n", "for count in range(n_rings):\n", " _components_data.append(\n", " {\"component\": components.DC_halfring,\n", " \"params\": {\"f\": circuit.f},\n", " \"component_id\": f\"dc_{count}\"})\n", "\n", " _components_data.append(\n", " {\"component\": components.Waveguide,\n", " \"params\": {\"f\": circuit.f, \"length\": np.pi * 5e-6},\n", " \"component_id\": f\"wg_{count}\"})\n", "\n", "bulk_add_component(circuit, _components_data)\n", "\n", "circuit.add_component(components.GC, component_id=\"input\")\n", "circuit.add_component(components.GC, component_id=\"output\")\n", "\n", "# bulk connect\n", "prev_comp = \"\"\n", "for count in range(n_rings):\n", " if count == 0:\n", " circuit.connect(\"input\", 1, f\"dc_{count}\", 0)\n", " circuit.connect(f\"dc_{count}\", 1, f\"wg_{count}\", 0)\n", " circuit.connect(f\"wg_{count}\", 1, f\"dc_{count}\", 3)\n", " prev_comp = \"dc_0\"\n", "\n", " elif count >= 1:\n", " circuit.connect(prev_comp, 2, f\"dc_{count}\", 0)\n", " circuit.connect(f\"dc_{count}\", 1, f\"wg_{count}\", 0)\n", " circuit.connect(f\"wg_{count}\", 1, f\"dc_{count}\", 3)\n", " prev_comp = f\"dc_{count}\"\n", "\n", "circuit.connect(prev_comp, 2, \"output\", 1)\n", "\n", "circuit.simulate_network()\n", "timer_stop = time.perf_counter()\n", "sim_time = timer_stop - timer_start\n", "print(f\"simulation finished in {sim_time} s\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With multiprocessing enabled, we can get speed-ups of upto 30-40%. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here are multiprocessing results for different values of `n` on an `AMD Ryzen 9 5900X 12-Core Processor`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
n_countt_normal (s)t_mp (s)speed-up(%)
0100.121.07-7.916667
11001.091.59-0.458716
2100011.588.080.302245
310000221.40140.950.363369
420000693.65409.240.410019
5250001085.94602.270.445393
\n", "
" ], "text/plain": [ " n_count t_normal (s) t_mp (s) speed-up(%)\n", "0 10 0.12 1.07 -7.916667\n", "1 100 1.09 1.59 -0.458716\n", "2 1000 11.58 8.08 0.302245\n", "3 10000 221.40 140.95 0.363369\n", "4 20000 693.65 409.24 0.410019\n", "5 25000 1085.94 602.27 0.445393" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_pickle(\"../_static/_data/mp_log_data.pkl\")\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For smaller circuits, there is a `penalty` for creating sub-processes. This is something to keep in mind when using OPICS multiprocessing. However, for large circuits, we observed `speed-ups of up to 45%`." ] } ], "metadata": { "interpreter": { "hash": "b1807c3e8799192c8ef0a1976ee6a1ff9a5e2f25907ec9b4426f1eb7e23bfc59" }, "kernelspec": { "display_name": "Python 3.8.8 ('base')", "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.8.8" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }