{
"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", "