diff --git a/docs/_config.yml b/docs/_config.yml index 29c55a2a..98beccc7 100755 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -27,7 +27,6 @@ execute: - "*meep_*" - "*meow_01*" - "*femwell_01_modes*" - - "*luminescent*" - "*pso*" - "*mpb*" # - "*20_schematic_driven_layout*" diff --git a/notebooks/luminescent.ipynb b/notebooks/luminescent.ipynb index c39885fe..b348ce14 100644 --- a/notebooks/luminescent.ipynb +++ b/notebooks/luminescent.ipynb @@ -6,9 +6,12 @@ "metadata": {}, "source": [ "# FDTD Luminescent Simulation and Inverse Design\n", - "v0.2.12-beta\n", - "2024/12/06 \n", - "Paul Shen " + "\n", + "v0.3-beta \n", + "2024/12 \n", + "Paul Shen \n", + "\n", + "Open https://colab.research.google.com/github/paulxshen/Luminescent.jl/blob/master/Luminescent_AI_docs.ipynb if you can't see ouput figures or table of contents." ] }, { @@ -74,13 +77,24 @@ "source": [ "## Geometry layout\n", "We layout using Python gdsfactory which is integrated with KLayout. Can also import .gds into gdsfactory . Internally, gdsfactory component and layer stack let generate a 3D mesh which is clipped vertically some depths above and below `core_layer`. By default,\n", - "we apply a SOI 220nm node (Si, SiO, SiN and Ge layers) implemented by [`gdsfactory.generic_tech`](https://gdsfactory.github.io/gdsfactory/notebooks/03_layer_stack.html#layerstack) layer stack. `luminescent.MATERIALS` maps the material tag of a layer in the layer stack to its property eg `MATERIALS[\"si\"][\"epsilon\"]`. Can create your own LAYER_STACK and MATERIALS for your process node." + "we apply a SOI 220nm node (Si, SiO, SiN and Ge layers) implemented by [`gdsfactory.generic_tech`](https://gdsfactory.github.io/gdsfactory/notebooks/03_layer_stack.html#layerstack) layer stack.\n" ] }, { "cell_type": "markdown", "id": "7", "metadata": {}, + "source": [ + "## Materials\n", + "We use Tidy3D's open source `materials_library`. We map gdsfactory layerstack layers to Tidy3D materials via the layer's material property while taking into account common name variants (eg \"si\" or \"Si\" mapping to \"cSi\").\n", + "\n", + "Dispersive, anisotropic, and nonlinear materials are by default not simulated but can be implemented upon request." + ] + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, "source": [ "## Margins and ports\n", "We automatically extend waveguides and adds margins during simulation but port locations remain fixed thus not affecting sparams. Port numbers map to gdsfactory component ports. Specify port pairs as eg `2,1` which is equivalent to `o2@0,o1@0` meaning optical_port_number@mode_number." @@ -88,7 +102,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "## Reciprocity and symmetry\n", @@ -97,33 +111,92 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "## File workflow\n", - "Each simulation or design optimization run is saved to a folder named after `name` arg or (if unnamed) timestamp string. These run folders are inside working directory `wd=\"~/luminescent_runs\"` which can be modified by passing to `write_sparams` or `gcell_problem`. Can access saved runs via `load_solution()`, `load_solution()`, `finetune()` which act on latest modified run folder inside `wd` if `name` not specified. " + "Each simulation or design optimization run is saved to a folder path. Can access saved runs via `load_res`, `finetune` " ] }, { "cell_type": "markdown", - "id": "10", + "id": "11", "metadata": {}, "source": [ - "# Installation\n", - "Backend CPU binaries at [releases](https://github.com/paulxshen/Luminescent.jl/releases) . GPU binaries can be requested\n", - "\n", - "## Windows\n", - "1. **Frontend**. Install Anaconda distribution of Python . Inside Anaconda Prompt do `pip install -U luminescent`\n", - "2. **Backend**. Unzip `LuminescentAI.zip` binaries. Add **where_you_unzipped**`\\LuminescentAI\\bin` to Path (using \"edit environmental variables\")\n", - " \n", - "## Linux\n", - "1. **Frontend**. `pip install -U luminescent`\n", - "2. **Backend**. TBD" + "# Installation\n" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", + "metadata": {}, + "source": [ + "## Frontend\n", + "If on Windows, Install Anaconda distribution of Python and use Anaconda Prompt for pip installs. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "%%shell\n", + "pip install -U luminescent &> /dev/null" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "## Backend\n", + "Install latest Julia. If on Windows, use [julialang.org](https://julialang.org). If on Linux, can do:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "%%shell\n", + "URL=\"https://julialang-s3.julialang.org/bin/linux/x64/1.11/julia-1.11.2-linux-x86_64.tar.gz\"\n", + "wget -nv $URL -O /tmp/julia.tar.gz # -nv means \"not verbose\"\n", + "tar -x -f /tmp/julia.tar.gz -C /usr/local --strip-components 1\n", + "rm /tmp/julia.tar.gz" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "Install FDTD (20min)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "%%shell\n", + "julia -e 'using Pkg; pkg\"add https://github.com/paulxshen/Luminescent.jl\"' &> /dev/null" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "id": "19", "metadata": {}, "source": [ "# Tutorials: PIC S-parameters simulation" @@ -131,7 +204,7 @@ }, { "cell_type": "markdown", - "id": "12", + "id": "20", "metadata": {}, "source": [ "## waveguide bend" @@ -139,7 +212,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "21", "metadata": {}, "source": [ "### 5um inner radius" @@ -147,11 +220,11 @@ }, { "cell_type": "markdown", - "id": "14", + "id": "22", "metadata": {}, "source": [ "#### Single wavelength 3D\n", - "We characterize insertion loss (IL) of waveguide bends wrt radius. We set R=5.0um, the often cited minimum radius in silicon photonics. First, we use `gdsfactory` to make the bend (note `gdsfactory` uses inner radius). Next, `write_sparams` simulates and saves results, which are retrieved and visualized by `load_solution`. \n", + "We characterize insertion loss (IL) of waveguide bends wrt radius. We set R=5.0um, the often cited minimum radius in silicon photonics. First, we use `gdsfactory` to make the bend (note `gdsfactory` uses inner radius). Next, we simulates and saves results, which are retrieved and visualized by `load_res`. \n", "\n", "`nres` is the maximum resolution - the number of points per wavelength in free space. The grid is adaptive so border regions actually use a lower resolution for speed. Remember FDTD scales as O(n^4)! `nres` has a huge effect on simulation time! Here, `nres=40` is accurate but can take half hour on CPU. `nres=20` is 16x faster and offers a reasonable estimate. Finally, Because of reciprocity we only need S or T param keys of \"2,1\". \n" ] @@ -159,10 +232,12 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "23", "metadata": {}, "outputs": [], "source": [ + "import os\n", + "\n", "import gdsfactory as gf\n", "import luminescent as lumi\n", "import numpy as np\n", @@ -171,27 +246,30 @@ "c = gf.components.bend_circular(radius=radius)\n", "# c.plot()\n", "\n", - "name = f\"bend_R{radius}\"\n", - "N = 3 # 3D or 2D\n", + "path = os.path.join(\"runs\", f\"bend_R{radius}\")\n", "wavelengths = 1.55\n", "keys = [\"2,1\"] # same as keys=[\"o2@0,o1@0\"]\n", - "nres = 40\n", + "nres = 30\n", + "dtype = \"float32\"\n", "\n", - "lumi.write_sparams(c, name=name, wavelengths=wavelengths, nres=nres, keys=keys, N=N)\n", - "sol = lumi.load_solution(name=name)" + "lumi.make_pic_sim_prob(\n", + " path, c, wavelengths=wavelengths, nres=nres, keys=keys, dtype=dtype\n", + ")\n", + "lumi.solve(path)\n", + "sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "16", + "id": "24", "metadata": {}, "source": [ - "Loss is <-0.01dB, which is lower than reported by [Tidy3D example](https://www.flexcompute.com/tidy3d/examples/notebooks/EulerWaveguideBend/)" + "Loss is -0.02dB, similar to [Tidy3D example](https://www.flexcompute.com/tidy3d/examples/notebooks/EulerWaveguideBend/)" ] }, { "cell_type": "markdown", - "id": "17", + "id": "25", "metadata": {}, "source": [ "#### Wavelength range 3D\n", @@ -201,29 +279,36 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "26", "metadata": {}, "outputs": [], "source": [ - "name = f\"bend_R{radius}_multi\"\n", + "path = os.path.join(\"runs\", f\"bend_R{radius}_multi\")\n", "wavelengths = np.linspace(1.5, 1.6, 5) # number or list or array\n", "\n", - "lumi.write_sparams(c, name=name, wavelengths=wavelengths, nres=nres, keys=keys, N=N)\n", - "sol = lumi.load_solution(name=name)" + "lumi.make_pic_sim_prob(\n", + " path,\n", + " c,\n", + " wavelengths=wavelengths,\n", + " nres=nres,\n", + " keys=keys,\n", + ")\n", + "lumi.solve(path)\n", + "sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "19", + "id": "27", "metadata": {}, "source": [ "#### Quickie 2.5D approximation \n", - "Set `N=2` to do a 2.5D simulation using (Ex, Ey, Hz) on a 2D plane with an \"effective\" refractive index integrated from a vertical modal profile. This is significantly faster but not accurate. Nevertheless it's a good way of exploring various geometries." + "Set `approx_2D_mode=\"TE\"` to do a 2.5D simulation using (Ex, Ey, Hz) on a 2D plane with an \"effective\" refractive index integrated from a vertical modal profile. This is significantly faster but not accurate. Nevertheless it's a good way of exploring various geometries." ] }, { "cell_type": "markdown", - "id": "20", + "id": "28", "metadata": {}, "source": [ "### 1.5um inner radius\n", @@ -233,21 +318,22 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "29", "metadata": {}, "outputs": [], "source": [ "radius = 1.5\n", - "name = f\"bend_R{radius}\"\n", + "path = os.path.join(\"runs\", f\"bend_R{radius}\")\n", "c = gf.components.bend_circular(radius=radius, allow_min_radius_violation=True)\n", "\n", - "lumi.write_sparams(c, name=name, wavelengths=wavelengths, nres=nres, keys=keys, N=N)\n", - "sol = lumi.load_solution(name=name)" + "lumi.make_pic_sim_prob(path, c, wavelengths=wavelengths, nres=nres, keys=keys)\n", + "lumi.solve(path)\n", + "sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "22", + "id": "30", "metadata": {}, "source": [ "Loss increased to 0.11dB" @@ -255,7 +341,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "31", "metadata": {}, "source": [ "## customizing materials, layers, and modes" @@ -264,14 +350,14 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "32", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", - "id": "25", + "id": "33", "metadata": {}, "source": [ "#### Defaults" @@ -280,28 +366,27 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "34", "metadata": {}, "outputs": [], "source": [ - "import gdsfactory as gf\n", - "import luminescent as lumi\n", - "from gdsfactory.generic_tech import LAYER, LAYER_STACK\n", - "from luminescent import MATERIALS\n", + "# import luminescent as lumi\n", + "# from gdsfactory.generic_tech import LAYER,LAYER_STACK\n", + "# import gdsfactory as gf\n", + "# import pprint as pp\n", "\n", - "core_layer = LAYER.WG\n", - "bbox_layer = LAYER.WAFER\n", - "layer_stack = LAYER_STACK\n", - "materials = MATERIALS\n", + "# core_layer=LAYER.WG\n", + "# bbox_layer=LAYER.WAFER\n", + "# layer_stack=LAYER_STACK\n", "\n", - "N = 3\n", - "dtype = \"float32\"\n", - "gpu = None" + "# N=3\n", + "# dtype=\"float32\"\n", + "# gpu=None" ] }, { "cell_type": "markdown", - "id": "27", + "id": "35", "metadata": {}, "source": [ "#### TE1" @@ -310,32 +395,24 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "36", "metadata": {}, "outputs": [], "source": [ - "c = gf.components.straight(length=1.0, width=0.5, layer=core_layer)\n", - "wavelengths = 1.55\n", - "nres = 30\n", + "# c = gf.components.straight(length=1.0,width=0.5,layer=core_layer)\n", + "# wavelengths=1.55\n", + "# nres=30\n", "\n", - "name = \"TE1\"\n", - "keys = [\"o2@1,o1@1\"]\n", - "lumi.write_sparams(\n", - " c,\n", - " name=name,\n", - " wavelengths=wavelengths,\n", - " keys=keys,\n", - " nres=nres,\n", - " N=N,\n", - " dtype=dtype,\n", - " gpu=gpu,\n", - ")\n", - "lumi.load_solution(name=name)" + "# path=\"TE1\"\n", + "# keys=[\"o2@1,o1@1\"]\n", + "# lumi.make_pic_sim_prob(path,c, wavelengths=wavelengths, keys=keys,nres=nres, dtype=dtype, gpu=gpu)\n", + "# lumi.solve(path)\n", + "# lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "29", + "id": "37", "metadata": {}, "source": [ "### Si rib waveguide\n", @@ -345,30 +422,22 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "38", "metadata": {}, "outputs": [], "source": [ - "name = \"rib\"\n", - "keys = [\"2,1\"]\n", - "bbox_layer = [LAYER.WAFER, LAYER.SLAB90]\n", - "lumi.write_sparams(\n", - " c,\n", - " name=name,\n", - " wavelengths=wavelengths,\n", - " keys=keys,\n", - " nres=nres,\n", - " N=N,\n", - " dtype=dtype,\n", - " gpu=gpu,\n", - " bbox_layer=bbox_layer,\n", - ")\n", - "sol = lumi.load_solution(name=name)" + "# path=\"rib\"\n", + "# keys=[\"2,1\"]\n", + "# bbox_layer=[LAYER.WAFER,LAYER.SLAB90]\n", + "# lumi.make_pic_sim_prob(path,c, wavelengths=wavelengths, keys=keys,nres=nres, dtype=dtype, gpu=gpu,\n", + "# bbox_layer=bbox_layer)\n", + "# lumi.solve(path)\n", + "# sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "31", + "id": "39", "metadata": {}, "source": [ "### SiN strip waveguide" @@ -377,48 +446,40 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "40", "metadata": {}, "outputs": [], "source": [ - "name = \"SiN\"\n", - "core_layer = LAYER.WGN\n", - "c = gf.components.straight(length=2.0, width=1.0, layer=core_layer)\n", + "# path=\"SiN\"\n", + "# core_layer=LAYER.WGN\n", + "# c = gf.components.straight(length=2.0, width=1.0, layer=core_layer)\n", "\n", - "lumi.write_sparams(\n", - " c,\n", - " name=name,\n", - " wavelengths=wavelengths,\n", - " keys=keys,\n", - " nres=nres,\n", - " N=N,\n", - " dtype=dtype,\n", - " gpu=gpu,\n", - " core_layer=core_layer,\n", - ")\n", - "sol = lumi.load_solution(name=name)" + "# lumi.make_pic_sim_prob(path,c, wavelengths=wavelengths, keys=keys,nres=nres, dtype=dtype, gpu=gpu,\n", + "# core_layer=core_layer)\n", + "# lumi.solve(path)\n", + "# sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "33", + "id": "41", "metadata": {}, "source": [ "# Tutorials: PIC generative inverse design\n", "We introduce GCells (generative cells), a natural evolution of PCells (parametric cells) in semiconductor design . Given a set of inverse design objectives, a GCell will generate optimal geometry using adjoint optimization while ensuring manufacturability by enforcing minimum feature lengths.\n", "\n", - "In examples below, `gcells.mimo` (multi in multi out) is just a gdsfactory component with configurable waveguide ports, simple slab as pre-optimization geometry, and overlying rectangular design regions. Dimensions `l` along x and `w` along y. Ports are numbered incrementally: west (SW->NW) -> east (SE->NE) -> south (SW->SE) -> north (NW->NE). By default, they're spaced equally on a side. Example: `west=1, east=2` places port 1 on west, ports 2 & 3 on east. But can also individually specify their locations and widths. Example : `west=[1.0, 2.5], wwg_west=[0.5, 0.4]`.\n", + "In examples below, `mimo` (multi in multi out) is just a gdsfactory component with configurable waveguide ports, simple slab as pre-optimization geometry, and overlying rectangular design regions. Dimensions `l` along x and `w` along y. Ports are numbered incrementally: west (SW->NW) -> east (SE->NE) -> south (SW->SE) -> north (NW->NE). By default, they're spaced equally on a side. Example: `west=1, east=2` places port 1 on west, ports 2 & 3 on east. But can also individually specify their locations and widths. Example : `west=[1.0, 2.5], wwg_west=[0.5, 0.4]`.\n", "\n", "Optimization `targets` is a dictionary organized wrt target type & wavelength. Types include T-params (`tparams`, most common), phase difference (`phasediff`), S-params (`sparams`). Multiple types & wavelengths are possible & often necessary . Loss for each type is scaled automatically to vary from 0 to 1 usually . For example , `tparams` loss of 0.5 roughly means 50% of power going to wrong places.\n", "\n", "`lvoid` is minimum length scale for voids. No void features smaller than it (currently this isn't exact - contact us for a more precise algorithm). Similarly for `lsolid`. \n", "\n", - "`N=2` optimizes in 2.5D which serves as a fast initialization for 3D optimization. Examples done at low resolution and lax convergence in 2.5D on CPU. For accuracy, the result must be finetuned in 3D at finer resolution, a feature that can be requested from Luminescent AI .\n" + "Setting `approx_2D_mode=\"TE\"` (or \"TM\") optimizes in 2.5D which serves as a fast initialization for 3D optimization. Examples done at low resolution and lax convergence in 2.5D on CPU. For accuracy, the result must be finetuned in 3D at finer resolution, a feature that can be requested from Luminescent AI .\n" ] }, { "cell_type": "markdown", - "id": "34", + "id": "42", "metadata": {}, "source": [ "## Generative cells PDK for passive devices \n" @@ -426,44 +487,51 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "43", "metadata": {}, "source": [ - "### mode converter\n", - "We target \"o2@1,o1@0\", converting optical port 1 mode TE0 input to optical port 2 mode TE1 output at 1.55um. Mode converters are notoriously hard to design, but generative AI does it in a pinch! " + "### wavelength domain demultiplexer" ] }, { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "44", "metadata": {}, "outputs": [], "source": [ - "# recommended RAM: >16G\n", + "# RAM: 20G\n", + "import os\n", + "\n", "import luminescent as lumi\n", "\n", - "name = \"mode_converter\" # can be any string\n", - "c = lumi.gcells.mimo(west=1, east=1, l=5.0, w=2.4, wwg=0.5, taper=0.05)\n", - "targets = {\"tparams\": {1.55: {\"o2@1,o1@0\": 1.0}}}\n", + "path = os.path.join(\"runs\", \"demux\")\n", + "c = lumi.mimo(west=1, east=2, l=3, w=3, wwg=0.5, taper=0.05)\n", + "targets = {\n", + " \"tparams\": {\n", + " 1.55: {\"2,1\": 1.0},\n", + " 1.20: {\"3,1\": 1.0},\n", + " }\n", + "}\n", "\n", - "prob = lumi.gcell_problem(\n", + "lumi.make_pic_inv_prob(\n", + " path,\n", " c,\n", " targets,\n", - " name=name,\n", - " N=2,\n", - " nres=15,\n", " lvoid=0.15,\n", " lsolid=0.15,\n", - " iters=100,\n", + " nres=15,\n", + " approx_2D_mode=\"TE\",\n", " stoploss=0.05,\n", + " iters=80,\n", ")\n", - "lumi.solve(prob)" + "lumi.solve(path)\n", + "sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "37", + "id": "45", "metadata": {}, "source": [ "Can optionally optimize more using `finetune`" @@ -472,17 +540,16 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "46", "metadata": {}, "outputs": [], "source": [ - "# import luminescent as lumi\n", - "# lumi.finetune(iters=40,name=\"mode_converter\")" + "# lumi.finetune(path,iters=40)" ] }, { "cell_type": "markdown", - "id": "39", + "id": "47", "metadata": {}, "source": [ "Lets see simulation fields and optimized geometry. Note the lax convergence criteria (`stoploss=.05`) means the solution isn't perfect." @@ -491,42 +558,35 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "48", "metadata": {}, "outputs": [], "source": [ - "name = \"mode_converter\"\n", - "sol = lumi.load_solution(name=name)" + "sol = lumi.load_res(path)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "41", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", - "id": "42", + "id": "49", "metadata": {}, "source": [ "### 1x2 splitter MMI\n", - "1.55um wavelength 1x2 splitter. We set symmetry about y so only need to specify T21=.5 as optimization target. Data saved to `name` folder inside working directory. We start iteratiions of adjoint optimization." + "1.55um wavelength 1x2 splitter. We set symmetry about y so only need to specify T21=.5 as optimization target. Data saved to `path` folder inside working directory. We start iteratiions of adjoint optimization." ] }, { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "50", "metadata": {}, "outputs": [], "source": [ + "import os\n", + "\n", "import luminescent as lumi\n", "\n", - "name = \"splitter\"\n", - "c = lumi.gcells.mimo(\n", + "path = os.path.join(\"runs\", \"splitter\")\n", + "c = lumi.mimo(\n", " west=1,\n", " east=2,\n", " l=4.0,\n", @@ -538,49 +598,25 @@ " \"tparams\": {1.55: {\"2,1\": 0.5}},\n", "}\n", "\n", - "prob = lumi.gcell_problem(\n", + "lumi.make_pic_inv_prob(\n", + " path,\n", " c,\n", " targets,\n", - " name=name,\n", - " N=2,\n", " nres=15,\n", " symmetries=[1],\n", " lvoid=0.15,\n", " lsolid=0.15,\n", " iters=50,\n", " stoploss=0.05,\n", + " approx_2D_mode=\"TE\",\n", ")\n", - "lumi.solve(prob, run=False)" - ] - }, - { - "cell_type": "markdown", - "id": "44", - "metadata": {}, - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45", - "metadata": {}, - "outputs": [], - "source": [ - "name = \"splitter\"\n", - "sol = lumi.load_solution(name=name)" + "lumi.solve(path)\n", + "sol = lumi.load_res(path)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "46", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", - "id": "47", + "id": "51", "metadata": {}, "source": [ "### 1x4 splitter MMI\n", @@ -590,76 +626,51 @@ { "cell_type": "code", "execution_count": null, - "id": "48", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "49", + "id": "52", "metadata": {}, "outputs": [], "source": [ - "# finetune(iters=10,name=name)\n", - "sol = lumi.load_solution(name)" + "# finetune(iters=10,path)\n", + "# sol = lumi.load_res(path)" ] }, { "cell_type": "markdown", - "id": "50", + "id": "53", "metadata": {}, "source": [ - "### wavelength domain demultiplexer" + "### mode converter\n", + "We target \"o2@1,o1@0\", converting optical port 1 mode TE0 input to optical port 2 mode TE1 ouput at 1.55um. Mode converters are notoriously hard to design, but generative AI does it in a pinch! " ] }, { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "54", "metadata": {}, "outputs": [], "source": [ - "# RAM: 32G\n", - "import luminescent as lumi\n", + "# recommended RAM: >16G\n", + "# import luminescent as lumi\n", + "# import os\n", "\n", - "name = \"demux\"\n", - "c = lumi.gcells.mimo(west=1, east=2, l=4.0, w=4.0, wwg=0.5)\n", - "targets = {\n", - " \"tparams\": {\n", - " 1.55: {\"2,1\": 1.0},\n", - " 1.20: {\"3,1\": 1.0},\n", - " }\n", - "}\n", + "# path = os.path.join(\"runs\",\"mode_converter\")\n", + "# c = lumi.mimo(west=1, east=1, l=5.0, w=2.4,\n", + "# wwg=.5, taper=.05)\n", + "# targets = {\"tparams\": {1.55: {\"o2@1,o1@0\": 1.0}}}\n", "\n", - "prob = lumi.gcell_problem(\n", - " c, targets, name=name, lvoid=0.15, lsolid=0.15, nres=15, N=2, iters=50\n", - ")\n", - "lumi.solve(prob)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52", - "metadata": {}, - "outputs": [], - "source": [ - "name = \"demux\"\n", - "sol = lumi.load_solution(name)" + "# lumi.make_pic_inv_prob(\n", + "# path,c, targets,\n", + "# approx_2D_mode=\"TE\", nres=15,\n", + "# lvoid=0.15, lsolid=.15,\n", + "# iters=100, stoploss=.05, )\n", + "# lumi.solve(path)\n", + "# lumi.load_res(path)" ] }, { - "attachments": {}, "cell_type": "markdown", - "id": "53", - "metadata": {}, - "source": [] - }, - { - "cell_type": "markdown", - "id": "54", + "id": "55", "metadata": {}, "source": [ "### symmetric crossing " @@ -668,38 +679,23 @@ { "cell_type": "code", "execution_count": null, - "id": "55", + "id": "56", "metadata": {}, "outputs": [], "source": [ - "import luminescent as lumi\n", + "# from pprint import pprint\n", + "# import luminescent as lumi\n", "\n", - "name = \"crossing\"\n", - "c = lumi.gcells.mimo(west=1, east=1, south=1, north=1, l=4.0, w=4.0, wwg=0.5)\n", - "targets = {\"tparams\": {1.55: {\"2,1\": 1.0}}}\n", + "# path=os.path.join(\"runs\", \"crossing\")\n", + "# c = lumi.mimo(west=1, east=1, south=1, north=1, l=4.0, w=4.0, wwg=.5)\n", + "# targets = {\"tparams\":{1.55: {\"2,1\": 1.0}}}\n", "\n", - "prob = lumi.gcell_problem(\n", - " c,\n", - " targets,\n", - " name=name,\n", - " lvoid=0.15,\n", - " lsolid=0.15,\n", - " nres=15,\n", - " symmetries=[0, 1],\n", - " N=2,\n", - " iters=40,\n", - ")\n", - "lumi.solve(prob)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "56", - "metadata": {}, - "outputs": [], - "source": [ - "sol = lumi.load_solution(name)" + "# lumi.make_pic_inv_prob(\n", + "# path,c, targets,\n", + "# lvoid=0.15,lsolid=0.15, nres=15, symmetries=[0,1],\n", + "# approx_2D_mode=\"TE\", iters=40)\n", + "# lumi.solve(path)\n", + "# sol = lumi.load_res(path)" ] }, {