From 5a83172b4df9236bc67aa13df1909d870e105843 Mon Sep 17 00:00:00 2001 From: Lindo Ouseph Date: Wed, 12 Apr 2023 20:57:45 +0530 Subject: [PATCH 1/2] 3 snippets --- .gitignore | 4 +- notebooks/assign_ds_model.ipynb | 192 +++++++++++++++++++ notebooks/remove_unconnected_nets.ipynb | 237 +++++++++++++++++++++++ notebooks/stackup.json | 1 + notebooks/stackup_export.ipynb | 241 ++++++++++++++++++++++++ 5 files changed, 673 insertions(+), 2 deletions(-) create mode 100644 notebooks/assign_ds_model.ipynb create mode 100644 notebooks/remove_unconnected_nets.ipynb create mode 100644 notebooks/stackup.json create mode 100644 notebooks/stackup_export.ipynb diff --git a/.gitignore b/.gitignore index 9a772ac3ac..8198151a23 100644 --- a/.gitignore +++ b/.gitignore @@ -82,8 +82,8 @@ doc/source/api/_autosummary target/ # Jupyter Notebook -.ipynb_checkpoints -notebooks/ +#.ipynb_checkpoints +#notebooks/ # IPython profile_default/ diff --git a/notebooks/assign_ds_model.ipynb b/notebooks/assign_ds_model.ipynb new file mode 100644 index 0000000000..2ba542f3bf --- /dev/null +++ b/notebooks/assign_ds_model.ipynb @@ -0,0 +1,192 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "659acad1", + "metadata": {}, + "source": [ + "# Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "de19eb7d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from ansys.edb.database import Database\n", + "from ansys.edb.session import launch_session\n", + "import ansys.edb as edb\n", + "from ansys.edb.definition.djordjecvic_sarkar_model import DjordjecvicSarkarModel\n", + "import json" + ] + }, + { + "cell_type": "markdown", + "id": "d817c01f", + "metadata": {}, + "source": [ + "# Configs" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "67bf7709", + "metadata": {}, + "outputs": [], + "source": [ + "ROOT = os.getcwd()\n", + "EXE_ROOT = os.environ['ANSYSEM_ROOT232']\n", + "EDB_FILE = r'D:\\2023\\PYEDB\\Galileo.aedb'" + ] + }, + { + "cell_type": "markdown", + "id": "6e0aeed6", + "metadata": {}, + "source": [ + "# Launch session" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "bac4d383", + "metadata": {}, + "outputs": [], + "source": [ + "session = launch_session(EXE_ROOT, 50051)" + ] + }, + { + "cell_type": "markdown", + "id": "ae0454f7", + "metadata": {}, + "source": [ + "# Open DB" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f88b342f", + "metadata": {}, + "outputs": [], + "source": [ + "db = Database.open(EDB_FILE,False)\n", + "cell = db.circuit_cells[0]\n", + "layout = cell.layout\n", + "layerStats = []\n", + "lc = layout.layer_collection\n", + "layers = lc.get_layers()\n", + "layer_names = [i.name for i in layers]" + ] + }, + { + "cell_type": "markdown", + "id": "71f27b0e", + "metadata": {}, + "source": [ + "# Extracting layer by layer information" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4313b4ed", + "metadata": {}, + "outputs": [], + "source": [ + "layer_info = []\n", + "for i in layers:\n", + " if i.is_stackup_layer:\n", + " name = i.name\n", + " layer_type = i.type.name\n", + " material = i.get_material().value\n", + " thickness = i.thickness.value\n", + " lower_elevation = i.lower_elevation.value\n", + " full_material = i.get_fill_material().value\n", + " \n", + " if 'DIELECTRIC_LAYER' in str(layer_type):\n", + " matmodel = edb.definition.material_def.MaterialDef.find_by_name(db,i.get_material().value)\n", + " ds = DjordjecvicSarkarModel.create()\n", + " matmodel.dielectric_material_model=ds \n", + " \n", + "db.save_as(r'D:\\2023\\PYEDB\\Galileo_modified.aedb')" + ] + }, + { + "cell_type": "markdown", + "id": "fa9042db", + "metadata": {}, + "source": [ + "# Write layer information to json file" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2e9c30af", + "metadata": {}, + "outputs": [], + "source": [ + "stackup_file = os.path.join(os.getcwd(),'stackup.json')\n", + "with open(stackup_file, 'w') as fp:\n", + " json.dump(layer_info, fp,indent=' ')" + ] + }, + { + "cell_type": "markdown", + "id": "0e7751ba", + "metadata": {}, + "source": [ + "# End the session" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f0750fb4", + "metadata": {}, + "outputs": [], + "source": [ + "session.disconnect()" + ] + }, + { + "cell_type": "markdown", + "id": "c302735a", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.9 64-bit", + "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.10.9" + }, + "vscode": { + "interpreter": { + "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/remove_unconnected_nets.ipynb b/notebooks/remove_unconnected_nets.ipynb new file mode 100644 index 0000000000..10179883b7 --- /dev/null +++ b/notebooks/remove_unconnected_nets.ipynb @@ -0,0 +1,237 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "659acad1", + "metadata": {}, + "source": [ + "# Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de19eb7d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from ansys.edb.database import Database\n", + "from ansys.edb.session import launch_session\n", + "import ansys.edb as edb\n", + "import json" + ] + }, + { + "cell_type": "markdown", + "id": "d817c01f", + "metadata": {}, + "source": [ + "# Configs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67bf7709", + "metadata": {}, + "outputs": [], + "source": [ + "ROOT = os.getcwd()\n", + "EXE_ROOT = os.environ['ANSYSEM_ROOT232']\n", + "EDB_FILE = r'D:\\2023\\PYEDB\\Galileo.aedb'" + ] + }, + { + "cell_type": "markdown", + "id": "6e0aeed6", + "metadata": {}, + "source": [ + "# Launch session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bac4d383", + "metadata": {}, + "outputs": [], + "source": [ + "session = launch_session(EXE_ROOT, 50051)" + ] + }, + { + "cell_type": "markdown", + "id": "ae0454f7", + "metadata": {}, + "source": [ + "# Open DB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f88b342f", + "metadata": {}, + "outputs": [], + "source": [ + "db = Database.open(EDB_FILE,False)\n", + "cell = db.circuit_cells[0]\n", + "layout = cell.layout\n", + "layerStats = []\n", + "lc = layout.layer_collection\n", + "layers = lc.get_layers()\n", + "layer_names = [i.name for i in layers]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e61f03f8", + "metadata": {}, + "outputs": [], + "source": [ + "nets = layout.nets\n", + "for net in nets:\n", + " netName = net.name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "071fbe9a", + "metadata": {}, + "outputs": [], + "source": [ + "for net in nets:\n", + " padstacks = net.padstack_instances\n", + " \n", + " if len(padstacks)==0 and net.name:\n", + " print(net.name)\n", + " # print(dir(net))\n", + " net.delete()\n", + "print(dir(db)) " + ] + }, + { + "cell_type": "markdown", + "id": "71f27b0e", + "metadata": {}, + "source": [ + "# Extracting layer by layer information" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4313b4ed", + "metadata": {}, + "outputs": [], + "source": [ + "layer_info = []\n", + "for i in layers:\n", + " if i.is_stackup_layer:\n", + " name = i.name\n", + " layer_type = i.type.name\n", + " material = i.get_material().value\n", + " thickness = i.thickness.value\n", + " lower_elevation = i.lower_elevation.value\n", + " full_material = i.get_fill_material().value\n", + " \n", + " if 'SIGNAL_LAYER' in str(layer_type):\n", + " matmodel = edb.definition.material_def.MaterialDef.find_by_name(db,i.get_material().value)\n", + " Sigma = matmodel.get_property(edb.definition.material_def.MaterialProperty.CONDUCTIVITY).value\n", + " x = (name,\n", + " layer_type,\n", + " material,\n", + " Sigma,\n", + " thickness,\n", + " lower_elevation,\n", + " full_material) \n", + " elif 'DIELECTRIC_LAYER' in str(layer_type):\n", + " matmodel = edb.definition.material_def.MaterialDef.find_by_name(db,i.get_material().value)\n", + " Td = matmodel.get_property(edb.definition.material_def.MaterialProperty.DIELECTRIC_LOSS_TANGENT).value\n", + " Er = matmodel.get_property(edb.definition.material_def.MaterialProperty.PERMITTIVITY).value\n", + " x = (name,\n", + " layer_type,\n", + " material,\n", + " Er,\n", + " Td,\n", + " thickness,\n", + " lower_elevation,\n", + " full_material)\n", + " layer_info.append(x)" + ] + }, + { + "cell_type": "markdown", + "id": "fa9042db", + "metadata": {}, + "source": [ + "# Write layer information to json file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e9c30af", + "metadata": {}, + "outputs": [], + "source": [ + "stackup_file = os.path.join(os.getcwd(),'stackup.json')\n", + "with open(stackup_file, 'w') as fp:\n", + " json.dump(layer_info, fp,indent=' ')" + ] + }, + { + "cell_type": "markdown", + "id": "0e7751ba", + "metadata": {}, + "source": [ + "# End the session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0750fb4", + "metadata": {}, + "outputs": [], + "source": [ + "session.disconnect()" + ] + }, + { + "cell_type": "markdown", + "id": "c302735a", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.9 64-bit", + "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.10.9" + }, + "vscode": { + "interpreter": { + "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/stackup.json b/notebooks/stackup.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/notebooks/stackup.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/notebooks/stackup_export.ipynb b/notebooks/stackup_export.ipynb new file mode 100644 index 0000000000..3e6e1f9165 --- /dev/null +++ b/notebooks/stackup_export.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "659acad1", + "metadata": {}, + "source": [ + "# Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de19eb7d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from ansys.edb.database import Database\n", + "from ansys.edb.session import launch_session\n", + "import ansys.edb as edb\n", + "from ansys.edb.definition.djordjecvic_sarkar_model import DjordjecvicSarkarModel\n", + "import json" + ] + }, + { + "cell_type": "markdown", + "id": "d817c01f", + "metadata": {}, + "source": [ + "# Configs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67bf7709", + "metadata": {}, + "outputs": [], + "source": [ + "ROOT = os.getcwd()\n", + "EXE_ROOT = os.environ['ANSYSEM_ROOT232']\n", + "EDB_FILE = r'D:\\2023\\PYEDB\\Galileo.aedb'" + ] + }, + { + "cell_type": "markdown", + "id": "6e0aeed6", + "metadata": {}, + "source": [ + "# Launch session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bac4d383", + "metadata": {}, + "outputs": [], + "source": [ + "session = launch_session(EXE_ROOT, 50051)" + ] + }, + { + "cell_type": "markdown", + "id": "ae0454f7", + "metadata": {}, + "source": [ + "# Open DB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f88b342f", + "metadata": {}, + "outputs": [], + "source": [ + "db = Database.open(EDB_FILE,False)\n", + "cell = db.circuit_cells[0]\n", + "layout = cell.layout\n", + "layerStats = []\n", + "lc = layout.layer_collection\n", + "layers = lc.get_layers()\n", + "layer_names = [i.name for i in layers]" + ] + }, + { + "cell_type": "markdown", + "id": "71f27b0e", + "metadata": {}, + "source": [ + "# Extracting layer by layer information" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "4313b4ed", + "metadata": {}, + "outputs": [ + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[11], line 22\u001b[0m\n\u001b[0;32m 14\u001b[0m x \u001b[38;5;241m=\u001b[39m (name,\n\u001b[0;32m 15\u001b[0m layer_type,\n\u001b[0;32m 16\u001b[0m material,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 19\u001b[0m lower_elevation,\n\u001b[0;32m 20\u001b[0m full_material) \n\u001b[0;32m 21\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mDIELECTRIC_LAYER\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mstr\u001b[39m(layer_type):\n\u001b[1;32m---> 22\u001b[0m matmodel \u001b[38;5;241m=\u001b[39m edb\u001b[38;5;241m.\u001b[39mdefinition\u001b[38;5;241m.\u001b[39mmaterial_def\u001b[38;5;241m.\u001b[39mMaterialDef\u001b[38;5;241m.\u001b[39mfind_by_name(db,\u001b[43mi\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_material\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mvalue)\n\u001b[0;32m 23\u001b[0m Td \u001b[38;5;241m=\u001b[39m matmodel\u001b[38;5;241m.\u001b[39mget_property(edb\u001b[38;5;241m.\u001b[39mdefinition\u001b[38;5;241m.\u001b[39mmaterial_def\u001b[38;5;241m.\u001b[39mMaterialProperty\u001b[38;5;241m.\u001b[39mDIELECTRIC_LOSS_TANGENT)\u001b[38;5;241m.\u001b[39mvalue\n\u001b[0;32m 24\u001b[0m Er \u001b[38;5;241m=\u001b[39m matmodel\u001b[38;5;241m.\u001b[39mget_property(edb\u001b[38;5;241m.\u001b[39mdefinition\u001b[38;5;241m.\u001b[39mmaterial_def\u001b[38;5;241m.\u001b[39mMaterialProperty\u001b[38;5;241m.\u001b[39mPERMITTIVITY)\u001b[38;5;241m.\u001b[39mvalue\n", + "File \u001b[1;32mD:\\2023\\PYEDB\\pyedb\\src\\ansys\\edb\\layer\\stackup_layer.py:151\u001b[0m, in \u001b[0;36mStackupLayer.get_material\u001b[1;34m(self, evaluated)\u001b[0m\n\u001b[0;32m 140\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mget_material\u001b[39m(\u001b[39mself\u001b[39m, evaluated\u001b[39m=\u001b[39m\u001b[39mTrue\u001b[39;00m):\n\u001b[0;32m 141\u001b[0m \u001b[39m \u001b[39m\u001b[39m\"\"\"Get the name of the material of the layer.\u001b[39;00m\n\u001b[0;32m 142\u001b[0m \n\u001b[0;32m 143\u001b[0m \u001b[39m Parameters\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 149\u001b[0m \u001b[39m str\u001b[39;00m\n\u001b[0;32m 150\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 151\u001b[0m \u001b[39mreturn\u001b[39;00m get_stackup_layer_stub()\u001b[39m.\u001b[39;49mGetMaterial(\n\u001b[0;32m 152\u001b[0m _get_layer_material_name_message(\u001b[39mself\u001b[39;49m, evaluated)\n\u001b[0;32m 153\u001b[0m )\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_interceptor.py:216\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable.__call__\u001b[1;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[0;32m 209\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m__call__\u001b[39m(\u001b[39mself\u001b[39m,\n\u001b[0;32m 210\u001b[0m request,\n\u001b[0;32m 211\u001b[0m timeout\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 214\u001b[0m wait_for_ready\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[0;32m 215\u001b[0m compression\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m):\n\u001b[1;32m--> 216\u001b[0m response, ignored_call \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_with_call(request,\n\u001b[0;32m 217\u001b[0m timeout\u001b[39m=\u001b[39;49mtimeout,\n\u001b[0;32m 218\u001b[0m metadata\u001b[39m=\u001b[39;49mmetadata,\n\u001b[0;32m 219\u001b[0m credentials\u001b[39m=\u001b[39;49mcredentials,\n\u001b[0;32m 220\u001b[0m wait_for_ready\u001b[39m=\u001b[39;49mwait_for_ready,\n\u001b[0;32m 221\u001b[0m compression\u001b[39m=\u001b[39;49mcompression)\n\u001b[0;32m 222\u001b[0m \u001b[39mreturn\u001b[39;00m response\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_interceptor.py:254\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._with_call\u001b[1;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[0;32m 251\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mException\u001b[39;00m \u001b[39mas\u001b[39;00m exception: \u001b[39m# pylint:disable=broad-except\u001b[39;00m\n\u001b[0;32m 252\u001b[0m \u001b[39mreturn\u001b[39;00m _FailureOutcome(exception, sys\u001b[39m.\u001b[39mexc_info()[\u001b[39m2\u001b[39m])\n\u001b[1;32m--> 254\u001b[0m call \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_interceptor\u001b[39m.\u001b[39;49mintercept_unary_unary(continuation,\n\u001b[0;32m 255\u001b[0m client_call_details,\n\u001b[0;32m 256\u001b[0m request)\n\u001b[0;32m 257\u001b[0m \u001b[39mreturn\u001b[39;00m call\u001b[39m.\u001b[39mresult(), call\n", + "File \u001b[1;32mD:\\2023\\PYEDB\\pyedb\\src\\ansys\\edb\\core\\interceptors.py:25\u001b[0m, in \u001b[0;36mInterceptor.intercept_unary_unary\u001b[1;34m(self, continuation, client_call_details, request)\u001b[0m\n\u001b[0;32m 23\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mintercept_unary_unary\u001b[39m(\u001b[39mself\u001b[39m, continuation, client_call_details, request):\n\u001b[0;32m 24\u001b[0m \u001b[39m \u001b[39m\u001b[39m\"\"\"Intercept a GRPC call.\"\"\"\u001b[39;00m\n\u001b[1;32m---> 25\u001b[0m response \u001b[39m=\u001b[39m continuation(client_call_details, request)\n\u001b[0;32m 27\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_post_process(response)\n\u001b[0;32m 29\u001b[0m \u001b[39mreturn\u001b[39;00m response\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_interceptor.py:241\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._with_call..continuation\u001b[1;34m(new_details, request)\u001b[0m\n\u001b[0;32m 236\u001b[0m (new_method, new_timeout, new_metadata, new_credentials,\n\u001b[0;32m 237\u001b[0m new_wait_for_ready,\n\u001b[0;32m 238\u001b[0m new_compression) \u001b[39m=\u001b[39m (_unwrap_client_call_details(\n\u001b[0;32m 239\u001b[0m new_details, client_call_details))\n\u001b[0;32m 240\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m--> 241\u001b[0m response, call \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_thunk(new_method)\u001b[39m.\u001b[39;49mwith_call(\n\u001b[0;32m 242\u001b[0m request,\n\u001b[0;32m 243\u001b[0m timeout\u001b[39m=\u001b[39;49mnew_timeout,\n\u001b[0;32m 244\u001b[0m metadata\u001b[39m=\u001b[39;49mnew_metadata,\n\u001b[0;32m 245\u001b[0m credentials\u001b[39m=\u001b[39;49mnew_credentials,\n\u001b[0;32m 246\u001b[0m wait_for_ready\u001b[39m=\u001b[39;49mnew_wait_for_ready,\n\u001b[0;32m 247\u001b[0m compression\u001b[39m=\u001b[39;49mnew_compression)\n\u001b[0;32m 248\u001b[0m \u001b[39mreturn\u001b[39;00m _UnaryOutcome(response, call)\n\u001b[0;32m 249\u001b[0m \u001b[39mexcept\u001b[39;00m grpc\u001b[39m.\u001b[39mRpcError \u001b[39mas\u001b[39;00m rpc_error:\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_interceptor.py:266\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable.with_call\u001b[1;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[0;32m 259\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mwith_call\u001b[39m(\u001b[39mself\u001b[39m,\n\u001b[0;32m 260\u001b[0m request,\n\u001b[0;32m 261\u001b[0m timeout\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 264\u001b[0m wait_for_ready\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[0;32m 265\u001b[0m compression\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m):\n\u001b[1;32m--> 266\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_with_call(request,\n\u001b[0;32m 267\u001b[0m timeout\u001b[39m=\u001b[39;49mtimeout,\n\u001b[0;32m 268\u001b[0m metadata\u001b[39m=\u001b[39;49mmetadata,\n\u001b[0;32m 269\u001b[0m credentials\u001b[39m=\u001b[39;49mcredentials,\n\u001b[0;32m 270\u001b[0m wait_for_ready\u001b[39m=\u001b[39;49mwait_for_ready,\n\u001b[0;32m 271\u001b[0m compression\u001b[39m=\u001b[39;49mcompression)\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_interceptor.py:254\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._with_call\u001b[1;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[0;32m 251\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mException\u001b[39;00m \u001b[39mas\u001b[39;00m exception: \u001b[39m# pylint:disable=broad-except\u001b[39;00m\n\u001b[0;32m 252\u001b[0m \u001b[39mreturn\u001b[39;00m _FailureOutcome(exception, sys\u001b[39m.\u001b[39mexc_info()[\u001b[39m2\u001b[39m])\n\u001b[1;32m--> 254\u001b[0m call \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_interceptor\u001b[39m.\u001b[39;49mintercept_unary_unary(continuation,\n\u001b[0;32m 255\u001b[0m client_call_details,\n\u001b[0;32m 256\u001b[0m request)\n\u001b[0;32m 257\u001b[0m \u001b[39mreturn\u001b[39;00m call\u001b[39m.\u001b[39mresult(), call\n", + "File \u001b[1;32mD:\\2023\\PYEDB\\pyedb\\src\\ansys\\edb\\core\\interceptors.py:25\u001b[0m, in \u001b[0;36mInterceptor.intercept_unary_unary\u001b[1;34m(self, continuation, client_call_details, request)\u001b[0m\n\u001b[0;32m 23\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mintercept_unary_unary\u001b[39m(\u001b[39mself\u001b[39m, continuation, client_call_details, request):\n\u001b[0;32m 24\u001b[0m \u001b[39m \u001b[39m\u001b[39m\"\"\"Intercept a GRPC call.\"\"\"\u001b[39;00m\n\u001b[1;32m---> 25\u001b[0m response \u001b[39m=\u001b[39m continuation(client_call_details, request)\n\u001b[0;32m 27\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_post_process(response)\n\u001b[0;32m 29\u001b[0m \u001b[39mreturn\u001b[39;00m response\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_interceptor.py:241\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._with_call..continuation\u001b[1;34m(new_details, request)\u001b[0m\n\u001b[0;32m 236\u001b[0m (new_method, new_timeout, new_metadata, new_credentials,\n\u001b[0;32m 237\u001b[0m new_wait_for_ready,\n\u001b[0;32m 238\u001b[0m new_compression) \u001b[39m=\u001b[39m (_unwrap_client_call_details(\n\u001b[0;32m 239\u001b[0m new_details, client_call_details))\n\u001b[0;32m 240\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m--> 241\u001b[0m response, call \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_thunk(new_method)\u001b[39m.\u001b[39;49mwith_call(\n\u001b[0;32m 242\u001b[0m request,\n\u001b[0;32m 243\u001b[0m timeout\u001b[39m=\u001b[39;49mnew_timeout,\n\u001b[0;32m 244\u001b[0m metadata\u001b[39m=\u001b[39;49mnew_metadata,\n\u001b[0;32m 245\u001b[0m credentials\u001b[39m=\u001b[39;49mnew_credentials,\n\u001b[0;32m 246\u001b[0m wait_for_ready\u001b[39m=\u001b[39;49mnew_wait_for_ready,\n\u001b[0;32m 247\u001b[0m compression\u001b[39m=\u001b[39;49mnew_compression)\n\u001b[0;32m 248\u001b[0m \u001b[39mreturn\u001b[39;00m _UnaryOutcome(response, call)\n\u001b[0;32m 249\u001b[0m \u001b[39mexcept\u001b[39;00m grpc\u001b[39m.\u001b[39mRpcError \u001b[39mas\u001b[39;00m rpc_error:\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_channel.py:955\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable.with_call\u001b[1;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[0;32m 948\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mwith_call\u001b[39m(\u001b[39mself\u001b[39m,\n\u001b[0;32m 949\u001b[0m request,\n\u001b[0;32m 950\u001b[0m timeout\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 953\u001b[0m wait_for_ready\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m,\n\u001b[0;32m 954\u001b[0m compression\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m):\n\u001b[1;32m--> 955\u001b[0m state, call, \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_blocking(request, timeout, metadata, credentials,\n\u001b[0;32m 956\u001b[0m wait_for_ready, compression)\n\u001b[0;32m 957\u001b[0m \u001b[39mreturn\u001b[39;00m _end_unary_response_blocking(state, call, \u001b[39mTrue\u001b[39;00m, \u001b[39mNone\u001b[39;00m)\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\grpc\\_channel.py:926\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._blocking\u001b[1;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[0;32m 924\u001b[0m \u001b[39mraise\u001b[39;00m rendezvous \u001b[39m# pylint: disable-msg=raising-bad-type\u001b[39;00m\n\u001b[0;32m 925\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[1;32m--> 926\u001b[0m call \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_channel\u001b[39m.\u001b[39;49msegregated_call(\n\u001b[0;32m 927\u001b[0m cygrpc\u001b[39m.\u001b[39;49mPropagationConstants\u001b[39m.\u001b[39;49mGRPC_PROPAGATE_DEFAULTS,\n\u001b[0;32m 928\u001b[0m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_method, \u001b[39mNone\u001b[39;49;00m, _determine_deadline(deadline), metadata,\n\u001b[0;32m 929\u001b[0m \u001b[39mNone\u001b[39;49;00m \u001b[39mif\u001b[39;49;00m credentials \u001b[39mis\u001b[39;49;00m \u001b[39mNone\u001b[39;49;00m \u001b[39melse\u001b[39;49;00m credentials\u001b[39m.\u001b[39;49m_credentials, ((\n\u001b[0;32m 930\u001b[0m operations,\n\u001b[0;32m 931\u001b[0m \u001b[39mNone\u001b[39;49;00m,\n\u001b[0;32m 932\u001b[0m ),), \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_context)\n\u001b[0;32m 933\u001b[0m event \u001b[39m=\u001b[39m call\u001b[39m.\u001b[39mnext_event()\n\u001b[0;32m 934\u001b[0m _handle_event(event, state, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_response_deserializer)\n", + "File \u001b[1;32msrc\\python\\grpcio\\grpc\\_cython\\_cygrpc/channel.pyx.pxi:496\u001b[0m, in \u001b[0;36mgrpc._cython.cygrpc.Channel.segregated_call\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32msrc\\python\\grpcio\\grpc\\_cython\\_cygrpc/channel.pyx.pxi:366\u001b[0m, in \u001b[0;36mgrpc._cython.cygrpc._segregated_call\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32msrc\\python\\grpcio\\grpc\\_cython\\_cygrpc/channel.pyx.pxi:360\u001b[0m, in \u001b[0;36mgrpc._cython.cygrpc._segregated_call\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32msrc\\python\\grpcio\\grpc\\_cython\\_cygrpc/channel.pyx.pxi:218\u001b[0m, in \u001b[0;36mgrpc._cython.cygrpc._call\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\threading.py:267\u001b[0m, in \u001b[0;36mCondition.__exit__\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m 264\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m__enter__\u001b[39m(\u001b[39mself\u001b[39m):\n\u001b[0;32m 265\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_lock\u001b[39m.\u001b[39m\u001b[39m__enter__\u001b[39m()\n\u001b[1;32m--> 267\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m__exit__\u001b[39m(\u001b[39mself\u001b[39m, \u001b[39m*\u001b[39margs):\n\u001b[0;32m 268\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_lock\u001b[39m.\u001b[39m\u001b[39m__exit__\u001b[39m(\u001b[39m*\u001b[39margs)\n\u001b[0;32m 270\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m__repr__\u001b[39m(\u001b[39mself\u001b[39m):\n", + "File \u001b[1;32m_pydevd_bundle/pydevd_cython.pyx:1457\u001b[0m, in \u001b[0;36m_pydevd_bundle.pydevd_cython.SafeCallWrapper.__call__\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32m_pydevd_bundle/pydevd_cython.pyx:1758\u001b[0m, in \u001b[0;36m_pydevd_bundle.pydevd_cython.ThreadTracer.__call__\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mc:\\Program Files\\Python310\\lib\\site-packages\\debugpy\\_vendored\\pydevd\\_pydev_bundle\\pydev_is_thread_alive.py:9\u001b[0m, in \u001b[0;36mis_thread_alive\u001b[1;34m(t)\u001b[0m\n\u001b[0;32m 6\u001b[0m _temp \u001b[39m=\u001b[39m threading\u001b[39m.\u001b[39mThread()\n\u001b[0;32m 7\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mhasattr\u001b[39m(_temp, \u001b[39m'\u001b[39m\u001b[39m_is_stopped\u001b[39m\u001b[39m'\u001b[39m): \u001b[39m# Python 3.x has this\u001b[39;00m\n\u001b[1;32m----> 9\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mis_thread_alive\u001b[39m(t):\n\u001b[0;32m 10\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mnot\u001b[39;00m t\u001b[39m.\u001b[39m_is_stopped\n\u001b[0;32m 12\u001b[0m \u001b[39melif\u001b[39;00m \u001b[39mhasattr\u001b[39m(_temp, \u001b[39m'\u001b[39m\u001b[39m_Thread__stopped\u001b[39m\u001b[39m'\u001b[39m): \u001b[39m# Python 2.x has this\u001b[39;00m\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "layer_info = []\n", + "for i in layers:\n", + " if i.is_stackup_layer:\n", + " name = i.name\n", + " layer_type = i.type.name\n", + " material = i.get_material().value\n", + " thickness = i.thickness.value\n", + " lower_elevation = i.lower_elevation.value\n", + " full_material = i.get_fill_material().value\n", + " \n", + " if 'SIGNAL_LAYER' in str(layer_type):\n", + " matmodel = edb.definition.material_def.MaterialDef.find_by_name(db,i.get_material().value)\n", + " Sigma = matmodel.get_property(edb.definition.material_def.MaterialProperty.CONDUCTIVITY).value\n", + " x = (name,\n", + " layer_type,\n", + " material,\n", + " Sigma,\n", + " thickness,\n", + " lower_elevation,\n", + " full_material) \n", + " elif 'DIELECTRIC_LAYER' in str(layer_type):\n", + " matmodel = edb.definition.material_def.MaterialDef.find_by_name(db,i.get_material().value)\n", + " Td = matmodel.get_property(edb.definition.material_def.MaterialProperty.DIELECTRIC_LOSS_TANGENT).value\n", + " Er = matmodel.get_property(edb.definition.material_def.MaterialProperty.PERMITTIVITY).value\n", + " x = (name,\n", + " layer_type,\n", + " material,\n", + " Er,\n", + " Td,\n", + " thickness,\n", + " lower_elevation,\n", + " full_material)\n", + " layer_info.append(x)\n", + "db.save_as(r'D:\\2023\\PYEDB\\Galileo_modified.aedb')" + ] + }, + { + "cell_type": "markdown", + "id": "fa9042db", + "metadata": {}, + "source": [ + "# Write layer information to json file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e9c30af", + "metadata": {}, + "outputs": [], + "source": [ + "stackup_file = os.path.join(os.getcwd(),'stackup.json')\n", + "with open(stackup_file, 'w') as fp:\n", + " json.dump(layer_info, fp,indent=' ')" + ] + }, + { + "cell_type": "markdown", + "id": "0e7751ba", + "metadata": {}, + "source": [ + "# End the session" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f0750fb4", + "metadata": {}, + "outputs": [], + "source": [ + "session.disconnect()" + ] + }, + { + "cell_type": "markdown", + "id": "c302735a", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.9 64-bit", + "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.10.9" + }, + "vscode": { + "interpreter": { + "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From f9259bb472d806b986483b7dc41f07e133629278 Mon Sep 17 00:00:00 2001 From: Lindo Ouseph Date: Wed, 21 Jun 2023 20:27:22 +0530 Subject: [PATCH 2/2] edb_plot_snippet --- notebooks/plot_nets.ipynb | 292 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 notebooks/plot_nets.ipynb diff --git a/notebooks/plot_nets.ipynb b/notebooks/plot_nets.ipynb new file mode 100644 index 0000000000..2615c820c6 --- /dev/null +++ b/notebooks/plot_nets.ipynb @@ -0,0 +1,292 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "de19eb7d", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"imports\"\"\"\n", + "import os\n", + "from ansys.edb.database import Database\n", + "from ansys.edb.session import launch_session\n", + "import ansys.edb as edb\n", + "import json\n", + "import subprocess\n", + "import psutil\n", + "import numpy as np\n", + "import sys\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib\n", + "from matplotlib.patches import Polygon\n", + "from matplotlib.collections import PatchCollection\n", + "from matplotlib import colors as mcolors\n", + "from matplotlib.collections import PatchCollection" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "67bf7709", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"configs\"\"\"\n", + "ROOT = os.getcwd()\n", + "EXE_ROOT = os.environ['ANSYSEM_ROOT232']\n", + "ROOT = os.getcwd()\n", + "EDB_FILE = os.path.join(ROOT,'data','meshed_ground.aedb')\n", + "# EDB_FILE = r'D:\\2023\\SAMSUNG\\One_Click_CIS_Automation_main\\5_4HB_FF_Vertical_211111\\5_4HB_FF_Vertical_211111.aedb'\n", + "out = os.path.join(ROOT,'data','stackup_export.aedb')\n", + "json_file = os.path.join(ROOT,'data','net_polygon_export.json')\n", + "python_script =os.path.join(ROOT,'plot_edb.py')\n", + "image_file = os.path.join(ROOT,'data','out.png')\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "bac4d383", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"launch session\"\"\"\n", + "PROCNAME = \"EDB_RPC_Server.exe\"\n", + "try:\n", + " for proc in psutil.process_iter():\n", + " if proc.name() == PROCNAME:\n", + " proc.kill()\n", + "except:\n", + " pass\n", + "session = launch_session(EXE_ROOT, 50051)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f88b342f", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"open db\"\"\"\n", + "db = Database.open(EDB_FILE,False)\n", + "cell = db.circuit_cells[0]\n", + "layout = cell.layout\n", + "layerStats = []\n", + "lc = layout.layer_collection\n", + "layers = lc.get_layers()\n", + "layer_names = [i.name for i in layers]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2a8b3a90", + "metadata": {}, + "outputs": [], + "source": [ + "def eval_arc_points(p1, p2, h, n=6, tol=1e-12):\n", + " import math\n", + " # fmt: off\n", + " if abs(h) < tol:\n", + " return [], []\n", + " elif h > 0:\n", + " reverse = False\n", + " x1 = p1[0]\n", + " y1 = p1[1]\n", + " x2 = p2[0]\n", + " y2 = p2[1]\n", + " else:\n", + " reverse = True\n", + " x1 = p2[0]\n", + " y1 = p2[1]\n", + " x2 = p1[0]\n", + " y2 = p1[1]\n", + " h *= -1\n", + " xa = (x2-x1) / 2\n", + " ya = (y2-y1) / 2\n", + " xo = x1 + xa\n", + " yo = y1 + ya\n", + " a = math.sqrt(xa**2 + ya**2)\n", + " if a < tol:\n", + " return [], []\n", + " r = (a**2)/(2*h) + h/2\n", + " if abs(r-a) < tol:\n", + " b = 0\n", + " th = 2 * math.asin(1) # chord angle\n", + " else:\n", + " b = math.sqrt(r**2 - a**2)\n", + " th = 2 * math.asin(a/r) # chord angle\n", + "\n", + " # center of the circle\n", + " xc = xo + b*ya/a\n", + " yc = yo - b*xa/a\n", + "\n", + " alpha = math.atan2((y1-yc), (x1-xc))\n", + " xr = []\n", + " yr = []\n", + " for i in range(n):\n", + " i += 1\n", + " dth = (i/(n+1)) * th\n", + " xi = xc + r * math.cos(alpha-dth)\n", + " yi = yc + r * math.sin(alpha-dth)\n", + " xr.append(xi)\n", + " yr.append(yi)\n", + "\n", + " if reverse:\n", + " xr.reverse()\n", + " yr.reverse()\n", + " # fmt: on\n", + " return xr, yr" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "5bf5bc37", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\louseph\\AppData\\Local\\Temp\\ipykernel_20620\\2202416059.py:65: MatplotlibDeprecationWarning: Passing the closed parameter of __init__() positionally is deprecated since Matplotlib 3.6; the parameter will become keyword-only two minor releases later.\n", + " pp = Polygon(P,True)\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nets = layout.nets\n", + "Poly={}\n", + "selected_nets=[]\n", + "selected_layers = []\n", + "Poly['voids'] = {}\n", + "for net in nets:\n", + " netName = net.name\n", + " if netName in selected_nets or len(selected_nets)==0:\n", + " prims = list(net.primitives)\n", + " Poly[netName] = {}\n", + " for c,prim in enumerate(prims):\n", + " # print(c)\n", + " if prim.layer.name in selected_layers or len(selected_layers)==0:\n", + " if prim.primitive_type.value==3:\n", + " width = prim.width.value\n", + " polygonData = prim.center_line.points\n", + " elif prim.primitive_type.value==2:\n", + " width = 0\n", + " polygonData = prim.polygon_data.points\n", + " elif prim.primitive_type.value==1:\n", + " width = 0\n", + " polygonData = prim.owner.polygon_data.points\n", + " else:\n", + " pass\n", + " \n", + " xy = [[float(i.x.value),float(i.y.value)] for i in polygonData]\n", + " Poly[netName]['{}'.format(c)] = [xy,width]\n", + " if prim.has_voids:\n", + " for void in prim.voids:\n", + " polygonData = void.get_polygon_data().points\n", + " xy = [[float(i.x.value),float(i.y.value)] for i in polygonData]\n", + " width=0\n", + " Poly['voids']['{}'.format(len(Poly['voids']))] = [xy,width]\n", + " \n", + "\n", + "dpi = '60'\n", + "ii = [float(j) for key in Poly for i in Poly[key] for k in Poly[key][i][0] if len(k)>1 for j in k]\n", + "xmin = min(ii[0::2]);xmax = max(ii[0::2])\n", + "ymin = min(ii[1::2]);ymax = max(ii[1::2])\n", + "\n", + "scale = 1e3\n", + "cm = (1/2.54)\n", + "W = abs(xmin-xmax)*cm*scale\n", + "H = abs(ymin-ymax)*cm*scale\n", + "\n", + "key = list(Poly.keys())\n", + "fig, ax = plt.subplots(frameon=False,dpi=None)\n", + "\n", + "golden_ratio_conjugate = 0.618033988749895\n", + "nn,alpha=18,.6\n", + "\n", + "c=[];patches = [];h = .2;x=[];y=[]\n", + "for key1 in Poly:\n", + " if key1 == 'voids':\n", + " continue\n", + " h += golden_ratio_conjugate\n", + " h %= 1\n", + " net_color = h\n", + " for key2 in Poly[key1]:\n", + " c.append(net_color)\n", + " P = Poly[key1][key2][0]\n", + " P = [i for i in P if len(i)>1 if max(i)<100]\n", + " # if max(P)>1e3:\n", + " # continue\n", + " pp = Polygon(P,True)\n", + " patches.append(pp)\n", + "name = ['turbo','nipy_spectral','gist_ncar','cubehelix','brg','gist_rainbow', 'rainbow', 'jet','flag', 'prism', 'ocean', 'gist_earth', 'terrain','flag', 'prism', 'ocean', 'gist_earth', 'terrain','tab20c','Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2','Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2','RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic','Wistia', 'hot', 'afmhot', 'gist_heat', 'copper''Wistia', 'hot', 'afmhot', 'gist_heat', 'copper','binary', 'gist_yarg', 'gist_gray', 'gray', 'bone','binary', 'gist_yarg', 'gist_gray', 'gray', 'bone','GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn', 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu','Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds','viridis', 'plasma', 'inferno', 'magma', 'cividis']\n", + "cmap = name[nn]\n", + "collection = PatchCollection(patches, cmap=matplotlib.colormaps[cmap], alpha=alpha,linewidths=(0,))\n", + "collection.set_array(c)\n", + "collection.set_linewidth(0)\n", + "collection.set_alpha(.2)\n", + "ax.add_collection(collection)\n", + "plt.xlim((xmin,xmax))\n", + "plt.ylim((ymin,ymax))\n", + "ax.set_axis_off()\n", + "ax.autoscale(enable=True)\n", + "# plt.gcf().set_size_inches(W, H)\n", + "plt.tight_layout()\n", + "plt.show()\n", + "# plt.savefig(image_file,bbox_inches='tight',dpi=dpi,transparent=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0750fb4", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"End the session\"\"\"\n", + "session.disconnect()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.9 64-bit", + "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.10.9" + }, + "vscode": { + "interpreter": { + "hash": "26de051ba29f2982a8de78e945f0abaf191376122a1563185a90213a26c5da77" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}