{ "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_count | \n", "t_normal (s) | \n", "t_mp (s) | \n", "speed-up(%) | \n", "
---|---|---|---|---|
0 | \n", "10 | \n", "0.12 | \n", "1.07 | \n", "-7.916667 | \n", "
1 | \n", "100 | \n", "1.09 | \n", "1.59 | \n", "-0.458716 | \n", "
2 | \n", "1000 | \n", "11.58 | \n", "8.08 | \n", "0.302245 | \n", "
3 | \n", "10000 | \n", "221.40 | \n", "140.95 | \n", "0.363369 | \n", "
4 | \n", "20000 | \n", "693.65 | \n", "409.24 | \n", "0.410019 | \n", "
5 | \n", "25000 | \n", "1085.94 | \n", "602.27 | \n", "0.445393 | \n", "