{ "cells": [ { "cell_type": "markdown", "id": "18e8bea4-4ad1-40a0-acef-4fbd03d93f8e", "metadata": {}, "source": [ "# Simulations in `vipdopt`\n", "\n", "This notebook serves as an interactive guide to creating simulations in `vipdopt` to interface directly with the Lumerical FDTD solver. First run the below code to do the necessary setup and imports." ] }, { "cell_type": "code", "execution_count": 2, "id": "0f646cfd-bbd8-4acb-a0c1-6451a270f761", "metadata": { "scrolled": true }, "outputs": [], "source": [ "# imports\n", "from pathlib import Path\n", "import sys \n", "\n", "import numpy as np\n", "\n", "np.set_printoptions(threshold=100)\n", "\n", "# Get vipdopt directory path from Notebook\n", "parent_dir = str(Path().resolve().parents[2])\n", "\n", "# Add to sys.path\n", "sys.path.insert(0, parent_dir)\n", "\n", "# Imports from vipdopt\n", "from vipdopt.simulation import LumericalSimulation, LumericalSimObject, Monitor, Source, Import, LumericalFDTD" ] }, { "cell_type": "markdown", "id": "e6fa1723-dcbe-4b1c-a48e-697d689d5ce4", "metadata": {}, "source": [ "## Creating a New Simulation\n", "\n", "To create a simulation we must first instantiate a `LumericalSimulation` object. You can also load a simulation from [an appropiately formatted JSON file](#simulation-configuration-files)." ] }, { "cell_type": "code", "execution_count": 3, "id": "936d7f1a-bfb0-4a4d-8f0c-85fd283c6d16", "metadata": {}, "outputs": [], "source": [ "sim = LumericalSimulation()\n", "\n", "loaded_sim = LumericalSimulation(source='simulation_example.json')" ] }, { "cell_type": "markdown", "id": "7f6bbada-a45b-4d19-82d3-7b150a71ad60", "metadata": {}, "source": [ "## Simulation Objects\n", "\n", "Once a simulation object has been created, it can be populated with objects. Simulation objects require three things:\n", "\n", "1. A name\n", "2. An `LumericalSimObjectType`, that is, the type of object to create in Lumerical (e.g. power, profile, dipole)\n", "3. Properties, the values that define the object\n", "\n", "The properties can be provided upon creation of the object, or manipulated after the fact." ] }, { "cell_type": "code", "execution_count": null, "id": "babb6fc0-8356-4a47-9081-ba2c646ad4be", "metadata": {}, "outputs": [], "source": [ "# Here we create an object through our simulation\n", "props = {\n", " 'x' : 0.0,\n", " 'y' : 0.4e-6,\n", " 'monitor type' : 'linear x',\n", "}\n", "\n", "power = sim.new_object('power', 'power', properties=props)\n", "\n", "# You can also create a standalone object and add it to your simulation\n", "\n", "source_1 = LumericalSimObject('source_1', 'dipole') \n", "sim.add_object(source_1)\n", "\n", "print(sim.objects)" ] }, { "cell_type": "markdown", "id": "3684414b-83db-46ee-bbe1-dc4a770d2a9b", "metadata": {}, "source": [ "Simulation objects can be edited with the update method, which works just like that of the builtin `dict` in Python. Simulation objects can also be edited using dictionary-like access to individual properties." ] }, { "cell_type": "code", "execution_count": null, "id": "dd739757-1bf4-46a4-8342-be1b4583b6c6", "metadata": {}, "outputs": [], "source": [ "# Using the update method\n", "source_props = {\n", " 'theta': 90,\n", "}\n", "\n", "source_1.update(x=0, y=0)\n", "source_1.update(**source_props) # You can also unpack a dictionary\n", "\n", "# The simulation's update_object method works in a similar fashion\n", "sim.update_object('source_1', phi=0)\n", "\n", "source_1" ] }, { "cell_type": "code", "execution_count": null, "id": "631bd6b2-cff4-4a5d-98df-b39a1566653e", "metadata": {}, "outputs": [], "source": [ "# Using dictionary access to change parameters and add new ones\n", "source_1['theta'] = 45\n", "source_1['z'] = 0\n", "\n", "source_1" ] }, { "cell_type": "markdown", "id": "077fb688-91f5-4395-8335-09c378619153", "metadata": {}, "source": [ "## Simulation Object Subclasses\n", "\n", "Because the different object types have unique properties and data from simulations, there are also subclasses of `LumericalSimObject` that better cater to their specific needs. These include:\n", "\n", "* `Monitor` (which is further split into the `Profile` and `Power` classes)\n", "* `Source` (which is further split into `DipoleSource`, `GaussianSource`, and `TFSFSource`)\n", "* `Import`" ] }, { "cell_type": "markdown", "id": "83fdaa89-803c-410c-899b-ab1efa8244b2", "metadata": {}, "source": [ "### `Monitor` Class\n", "\n", "The `Monitor` class has additional methods and attributes for accessing data from a previously ran simulation. In Lumerical, profile and power monitors measure specific data: \n", "\n", "* E field\n", "* H field\n", "* Poynting vector\n", "* transmission\n", "* power\n", "* source power\n", "\n", "When a `Monitor` is first created, these values are all set to `None`." ] }, { "cell_type": "code", "execution_count": null, "id": "6d1b56d0-2155-43a5-9509-262e676cfa03", "metadata": {}, "outputs": [], "source": [ "mon = Monitor('mon', 'power')\n", "\n", "print(mon.e) # will be None by default" ] }, { "cell_type": "markdown", "id": "492df45d-70a9-4d8d-988a-7bcaa16268d6", "metadata": {}, "source": [ "Once a simulation is run, files containing each monitor's data can be generated. `Monitor` objects will dynamically draw data from these files as needed, and repalce its data with placeholder values (`None`) when no longer needed, so as to save memory." ] }, { "cell_type": "code", "execution_count": null, "id": "56d353db-1c47-456f-8666-9bbdb8c372c1", "metadata": {}, "outputs": [], "source": [ "# Suppose simulation 'sim' was run and saved data to 'sim.fsp'\n", "# The data from mon1 would be saved to 'sim_mon1.npz'\n", "\n", "mon.set_source('sim_mon.npz') # Link our monitor to it's data file\n", "\n", "print(mon.e) # No longer None\n", "\n", "# Say we wanted the average absolute value of the electric field\n", "value = np.abs(mon.e).mean()\n", "\n", "# We no longer need the field in memory so we can clear it out; `value` remains the same\n", "mon.reset()\n", "\n", "print(f'The mean value of |E| is: {value}')" ] }, { "cell_type": "markdown", "id": "cb44af96-1b14-40a9-a943-f3f6e0ad3abb", "metadata": {}, "source": [ "### `Source` Class\n", "\n", "The `Source` class is made to represent the various light sources in a simulation. The main addition to the `Source` class is that it is hashable, so it can be used as a key in dictionaries.\n", "\n", "The `Source` class is currently required for creating figures of merit (see more [here](fom.ipynb#using-the-fom-class))" ] }, { "cell_type": "code", "execution_count": null, "id": "17346b34-c8a8-4397-8145-e3f21647ed11", "metadata": {}, "outputs": [], "source": [ "src1 = Source('src1', 'gaussian')\n", "src2 = Source('src2', 'dipole')\n", "\n", "# A dictionary that maps Sources to their type\n", "source_to_type = {src: src.obj_type for src in [src1, src2]}\n", "print(source_to_type)" ] }, { "cell_type": "markdown", "id": "e0401ebf-177f-4e20-8a80-0720c54d7501", "metadata": {}, "source": [ "### `Import` Class\n", "\n", "The `Import` class mirrors the import primitive in Lumerical. It is used to create a 3D geometry. If you wish to use `vipdopt` for optimization purposes, you will need to include at least one `Import` in your simulation, as it is responsible for creating the design space for a device.\n", "\n", "`Import` comes with two additional methods, `set_nk2` and `get_nk2` which mirrors Lumerical's import_nk2 script command. These just set and retrieve refractive index values (n and k) over a volume (defined by x, y, z). These methods are mainly used by the `LumericalOptimization` to step a design and import those changes into Lumerical, and can mainly be ignored." ] }, { "cell_type": "markdown", "id": "9dc10f43", "metadata": {}, "source": [ "## Simulation Configuration Files\n", "\n", "Above, we showed how to create a simulation in a Python script by adding objects\n", "one by one. This process can become rather cumbersome for more complex simulations. Therefore,\n", "we provide a simpler way for creating simulations: a simulation configuration file.\n", "\n", "A simulation configuration file is a JSON formatted file that contains all of the simulation objects.\n", "Every simulation object has the following format when serialized for JSON:\n", "\n", "```json\n", "\"name\": \"\",\n", "\"obj_type\": \"\",\n", "\"properties\": {\n", " \"prop1\": \"\",\n", " \"prop2\": \"\",\n", "}\n", "```\n", "\n", "The simulation file has an entry `\"objects\"` with a list containing each simulation\n", "object. There can also be an entry called `\"info\"` to provide additional information about\n", "a simulation, such as a name or the savefile path.\n", "\n", "For an example, see [simulation_example.json](simulation_example.json)\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "9cefce31", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"objects\": {\n", " \"FDTD\": {\n", " \"name\": \"FDTD\",\n", " \"obj_type\": \"fdtd\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"dimension\": \"3D\",\n", " \"x span\": 3.06e-06,\n", " \"y span\": 3.06e-06,\n", " \"z max\": 2.8049999999999994e-06,\n", " \"z min\": -2.2949999999999996e-06,\n", " \"simulation time\": 6.000000000000001e-13,\n", " \"index\": 1.5\n", " }\n", " },\n", " \"forward_src_x\": {\n", " \"name\": \"forward_src_x\",\n", " \"obj_type\": \"gaussian\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"forward_src_x\",\n", " \"angle theta\": 0.0,\n", " \"angle phi\": 0,\n", " \"polarization angle\": 0,\n", " \"direction\": \"Backward\",\n", " \"x span\": 6.12e-06,\n", " \"injection axis\": \"z-axis\",\n", " \"y span\": 6.12e-06,\n", " \"z\": 2.5499999999999997e-06,\n", " \"x\": 0.0,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07,\n", " \"waist radius w0\": 1e-06,\n", " \"distance from waist\": -5.099999999999998e-07\n", " }\n", " },\n", " \"forward_src_y\": {\n", " \"name\": \"forward_src_y\",\n", " \"obj_type\": \"gaussian\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"forward_src_y\",\n", " \"angle theta\": 0.0,\n", " \"angle phi\": 0,\n", " \"polarization angle\": 90,\n", " \"direction\": \"Backward\",\n", " \"x span\": 6.12e-06,\n", " \"injection axis\": \"z-axis\",\n", " \"y span\": 6.12e-06,\n", " \"z\": 2.5499999999999997e-06,\n", " \"x\": 0.0,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07,\n", " \"waist radius w0\": 1e-06,\n", " \"distance from waist\": -5.099999999999998e-07\n", " }\n", " },\n", " \"adj_src_0x\": {\n", " \"name\": \"adj_src_0x\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_0x\",\n", " \"x\": 5.1e-07,\n", " \"y\": 5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 0,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_0y\": {\n", " \"name\": \"adj_src_0y\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_0y\",\n", " \"x\": 5.1e-07,\n", " \"y\": 5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 90,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_1x\": {\n", " \"name\": \"adj_src_1x\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_1x\",\n", " \"x\": -5.1e-07,\n", " \"y\": 5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 0,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_1y\": {\n", " \"name\": \"adj_src_1y\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_1y\",\n", " \"x\": -5.1e-07,\n", " \"y\": 5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 90,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_2x\": {\n", " \"name\": \"adj_src_2x\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_2x\",\n", " \"x\": -5.1e-07,\n", " \"y\": -5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 0,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_2y\": {\n", " \"name\": \"adj_src_2y\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_2y\",\n", " \"x\": -5.1e-07,\n", " \"y\": -5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 90,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_3x\": {\n", " \"name\": \"adj_src_3x\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_3x\",\n", " \"x\": 5.1e-07,\n", " \"y\": -5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 0,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"adj_src_3y\": {\n", " \"name\": \"adj_src_3y\",\n", " \"obj_type\": \"dipole\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"adj_src_3y\",\n", " \"x\": 5.1e-07,\n", " \"y\": -5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"theta\": 90,\n", " \"phi\": 90,\n", " \"wavelength start\": 3.75e-07,\n", " \"wavelength stop\": 7.249999999999999e-07\n", " }\n", " },\n", " \"focal_monitor_0\": {\n", " \"name\": \"focal_monitor_0\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"focal_monitor_0\",\n", " \"monitor type\": \"point\",\n", " \"x\": 5.1e-07,\n", " \"y\": 5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"focal_monitor_1\": {\n", " \"name\": \"focal_monitor_1\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"focal_monitor_1\",\n", " \"monitor type\": \"point\",\n", " \"x\": -5.1e-07,\n", " \"y\": 5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"focal_monitor_2\": {\n", " \"name\": \"focal_monitor_2\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"focal_monitor_2\",\n", " \"monitor type\": \"point\",\n", " \"x\": -5.1e-07,\n", " \"y\": -5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"focal_monitor_3\": {\n", " \"name\": \"focal_monitor_3\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"focal_monitor_3\",\n", " \"monitor type\": \"point\",\n", " \"x\": 5.1e-07,\n", " \"y\": -5.1e-07,\n", " \"z\": -1.5299999999999998e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"transmission_monitor_0\": {\n", " \"name\": \"transmission_monitor_0\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"transmission_monitor_0\",\n", " \"monitor type\": \"2D Z-normal\",\n", " \"y\": 5.1e-07,\n", " \"y span\": 1.02e-06,\n", " \"z\": -1.5299999999999998e-06,\n", " \"x\": 5.1e-07,\n", " \"x span\": 1.02e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"transmission_monitor_1\": {\n", " \"name\": \"transmission_monitor_1\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"transmission_monitor_1\",\n", " \"monitor type\": \"2D Z-normal\",\n", " \"y\": 5.1e-07,\n", " \"y span\": 1.02e-06,\n", " \"z\": -1.5299999999999998e-06,\n", " \"x\": -5.1e-07,\n", " \"x span\": 1.02e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"transmission_monitor_2\": {\n", " \"name\": \"transmission_monitor_2\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"transmission_monitor_2\",\n", " \"monitor type\": \"2D Z-normal\",\n", " \"y\": -5.1e-07,\n", " \"y span\": 1.02e-06,\n", " \"z\": -1.5299999999999998e-06,\n", " \"x\": -5.1e-07,\n", " \"x span\": 1.02e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"transmission_monitor_3\": {\n", " \"name\": \"transmission_monitor_3\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"transmission_monitor_3\",\n", " \"monitor type\": \"2D Z-normal\",\n", " \"y\": -5.1e-07,\n", " \"y span\": 1.02e-06,\n", " \"z\": -1.5299999999999998e-06,\n", " \"x\": 5.1e-07,\n", " \"x span\": 1.02e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"transmission_focal_monitor_\": {\n", " \"name\": \"transmission_focal_monitor_\",\n", " \"obj_type\": \"power\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"transmission_focal_monitor_\",\n", " \"monitor type\": \"2D Z-normal\",\n", " \"y\": 0,\n", " \"y span\": 2.04e-06,\n", " \"z\": -1.5299999999999998e-06,\n", " \"x\": 0,\n", " \"x span\": 2.04e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"use source limits\": 1,\n", " \"frequency points\": 60\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " },\n", " \"PEC_screen\": {\n", " \"name\": \"PEC_screen\",\n", " \"obj_type\": \"rect\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"PEC_screen\",\n", " \"x\": 0,\n", " \"x span\": 3.5904e-06,\n", " \"y\": 0,\n", " \"y span\": 3.5904e-06,\n", " \"z min\": 2.193e-06,\n", " \"z max\": 2.346e-06,\n", " \"material\": \"PEC (Perfect Electrical Conductor)\"\n", " }\n", " },\n", " \"source_aperture\": {\n", " \"name\": \"source_aperture\",\n", " \"obj_type\": \"rect\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"source_aperture\",\n", " \"x\": 0,\n", " \"x span\": 2.04e-06,\n", " \"y\": 0,\n", " \"y span\": 2.04e-06,\n", " \"z min\": 2.193e-06,\n", " \"z max\": 2.346e-06,\n", " \"index\": 1.5\n", " }\n", " },\n", " \"design_import\": {\n", " \"name\": \"design_import\",\n", " \"obj_type\": \"import\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"design_import\",\n", " \"x span\": 2.04e-06,\n", " \"y span\": 2.04e-06,\n", " \"z min\": 0.0,\n", " \"z max\": 2.04e-06\n", " },\n", " \"n\": null,\n", " \"x\": [\n", " 1.0\n", " ],\n", " \"y\": [\n", " 1.0\n", " ],\n", " \"z\": [\n", " 1.0\n", " ]\n", " },\n", " \"design_mesh\": {\n", " \"name\": \"design_mesh\",\n", " \"obj_type\": \"mesh\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"design_mesh\",\n", " \"x\": 0,\n", " \"x span\": 3.06e-06,\n", " \"y\": 0,\n", " \"y span\": 3.06e-06,\n", " \"z min\": -5e-07,\n", " \"z max\": 2.54e-06,\n", " \"dx\": 5.0999999999999993e-08,\n", " \"dy\": 5.0999999999999993e-08,\n", " \"dz\": 5.0999999999999993e-08\n", " }\n", " },\n", " \"design_index_monitor\": {\n", " \"name\": \"design_index_monitor\",\n", " \"obj_type\": \"index\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"design_index_monitor\",\n", " \"x span\": 2.04e-06,\n", " \"monitor type\": \"3D\",\n", " \"y span\": 2.04e-06,\n", " \"z min\": 0.0,\n", " \"z max\": 2.04e-06,\n", " \"spatial interpolation\": \"nearest mesh cell\"\n", " }\n", " },\n", " \"design_efield_monitor\": {\n", " \"name\": \"design_efield_monitor\",\n", " \"obj_type\": \"profile\",\n", " \"info\": {\n", " \"name\": \"\"\n", " },\n", " \"properties\": {\n", " \"name\": \"design_efield_monitor\",\n", " \"x span\": 2.04e-06,\n", " \"monitor type\": \"3D\",\n", " \"y span\": 2.04e-06,\n", " \"z min\": 0.0,\n", " \"z max\": 2.04e-06,\n", " \"override global monitor settings\": 1,\n", " \"use wavelength spacing\": 1,\n", " \"frequency points\": 60,\n", " \"output Hx\": 0,\n", " \"output Hy\": 0,\n", " \"output Hz\": 0\n", " },\n", " \"src\": null,\n", " \"_tshape\": null,\n", " \"_fshape\": null,\n", " \"_e\": null,\n", " \"_h\": null,\n", " \"_p\": null,\n", " \"_t\": null,\n", " \"_sp\": null,\n", " \"_power\": null,\n", " \"_sync\": false\n", " }\n", " }\n", "}\n" ] } ], "source": [ "sim_file = 'simulation_example.json'\n", "\n", "sim = LumericalSimulation(sim_file)\n", "\n", "# Or alteratively,\n", "sim = LumericalSimulation()\n", "sim.load(sim_file)\n", "\n", "print(sim)" ] }, { "cell_type": "markdown", "id": "d7f11fff-4c58-4bee-ac60-b5279d1ffafc", "metadata": {}, "source": [ "## Connecting to Lumerical FDTD\n", "\n", "So far, all we've done is create a Python representation of a simulation, but to actually use it with Lumerical, we would typically use their provided API (`lumapi`). In `vipdopt`, a class `LumericalFDTD` is provided which effectively serves as a wrapper around `lumapi` functionality. It is responsible for the following:\n", "\n", "* Importing `LumericalSimulation`'s into Lumerical\n", "* Saving and running simulation jobs\n", "* Retrieving data from completed simulations\n", "* Managing resources to be used in running jobs" ] }, { "cell_type": "code", "execution_count": 6, "id": "ddea80fd-55c6-4a45-9387-e6b493c4aa6e", "metadata": {}, "outputs": [], "source": [ "# Creating the FDTD hook\n", "\n", "fdtd = LumericalFDTD()\n", "sim = LumericalSimulation('simulation_example.json')\n", "sim_file = 'sim.fsp' # Where Lumerical will save simulation data\n", "\n", "fdtd.connect() # This starts a Lumerical session\n", "\n", "fdtd.load(path=None, sim=sim) # Load simulation into Lumerical\n", "fdtd.save(sim_file) # Lumerical must have a file on the disk before running a job" ] }, { "cell_type": "markdown", "id": "f0034cbf-31c7-4c62-ace6-46c7e2f0a79d", "metadata": {}, "source": [ "There are two ways to run a simulation:\n", "\n", "1. Load into the fdtd and run (only runs the currently loaded simulation)\n", "2. Add it as a job `fdtd.addjob()` and use `fdtd.runjobs()`" ] }, { "cell_type": "code", "execution_count": 4, "id": "e468f088-d8a7-40b0-8d5f-d29c0225451a", "metadata": {}, "outputs": [], "source": [ "# Option 1\n", "fdtd.run()" ] }, { "cell_type": "code", "execution_count": 7, "id": "4da430b7-0a8f-4701-bf58-0335c0f8eb5b", "metadata": {}, "outputs": [], "source": [ "# Option 2\n", "\n", "fdtd.addjob(sim_file) # Add the simulation file to the job queue\n", "fdtd.runjobs()" ] }, { "cell_type": "code", "execution_count": 8, "id": "e27419c8-1fda-410b-9b6b-793a941bd303", "metadata": {}, "outputs": [], "source": [ "# Create individual data files for each Monitor\n", "fdtd.reformat_monitor_data([sim])\n", "\n", "fdtd.close() # End Lumerical session" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.5" } }, "nbformat": 4, "nbformat_minor": 5 }