diff --git a/.gitignore b/.gitignore index 39c585d..fa33597 100644 --- a/.gitignore +++ b/.gitignore @@ -131,4 +131,5 @@ dmypy.json my_notebooks .vscode results -cfg \ No newline at end of file +cfg +notebooks/plots/ \ No newline at end of file diff --git a/README.md b/README.md index 413c4d4..a4d62f3 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Neural Inverse Design of Nanostructures (NIDN) is a Python project by the Advanc
Neural Inverse Design of Nanostructures with PyTorch @@ -63,6 +63,10 @@ This project is based on: For more details than provided with NIDN on the forward models please refer to their docs. The adaptations of there code are in the folders [nidn/trcwa/](https://github.com/esa/NIDN/tree/main/nidn/trcwa) and [nidn/fdtd/](https://github.com/esa/NIDN/tree/main/nidn/fdtd). +Below you can see results of an exemplary optimization of a three-uniform-layer material to design a 1150nm filter. + +![Exemplary optimization of a three-uniform-layer material to design a 1150nm filter. | width=300](/examples/BP-filter-3layer-opt.gif) +![Exemplary optimization of a three-uniform-layer material to design a 1150nm filter. | width=300](/examples/BP-filter-3layer-eps.gif) ## Getting Started diff --git a/docs/Makefile b/docs/Makefile index d4bb2cb..92dd33a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -5,7 +5,7 @@ # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build -SOURCEDIR = . +SOURCEDIR = source BUILDDIR = _build # Put it first so that "make" without argument is like "make help". diff --git a/docs/make.bat b/docs/make.bat index 922152e..5001b3f 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -7,7 +7,7 @@ REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) -set SOURCEDIR=. +set SOURCEDIR=source set BUILDDIR=_build if "%1" == "" goto help diff --git a/docs/FDTD_setup_illustration_white_background.png b/docs/source/FDTD_setup_illustration_white_background.png similarity index 100% rename from docs/FDTD_setup_illustration_white_background.png rename to docs/source/FDTD_setup_illustration_white_background.png diff --git a/docs/NIDN_Scheme_v2.drawio.drawio.png b/docs/source/NIDN_Scheme_v2.drawio.drawio.png similarity index 100% rename from docs/NIDN_Scheme_v2.drawio.drawio.png rename to docs/source/NIDN_Scheme_v2.drawio.drawio.png diff --git a/docs/NIDN_logo.jpg b/docs/source/NIDN_logo.jpg similarity index 100% rename from docs/NIDN_logo.jpg rename to docs/source/NIDN_logo.jpg diff --git a/docs/conf.py b/docs/source/conf.py similarity index 99% rename from docs/conf.py rename to docs/source/conf.py index 4b2ad8d..81b36eb 100644 --- a/docs/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ author = "Pablo Gómez and Håvard Hem Toftevaag" # The full version, including alpha/beta/rc tags -release = "v0.0.1" +release = "v0.1.1" # -- General configuration --------------------------------------------------- diff --git a/docs/index.rst b/docs/source/index.rst similarity index 100% rename from docs/index.rst rename to docs/source/index.rst diff --git a/docs/radiflector_invdesign_explanation_v2.png b/docs/source/radiflector_invdesign_explanation_v2.png similarity index 100% rename from docs/radiflector_invdesign_explanation_v2.png rename to docs/source/radiflector_invdesign_explanation_v2.png diff --git a/docs/tutorial.rst b/docs/source/tutorial.rst similarity index 100% rename from docs/tutorial.rst rename to docs/source/tutorial.rst diff --git a/examples/BP-filter-3layer-eps.gif b/examples/BP-filter-3layer-eps.gif new file mode 100644 index 0000000..74d2e54 Binary files /dev/null and b/examples/BP-filter-3layer-eps.gif differ diff --git a/examples/BP-filter-3layer-opt.gif b/examples/BP-filter-3layer-opt.gif new file mode 100644 index 0000000..991b608 Binary files /dev/null and b/examples/BP-filter-3layer-opt.gif differ diff --git a/nidn/plots/plot_eps_per_point.py b/nidn/plots/plot_eps_per_point.py index 2eb7a90..a344a4e 100644 --- a/nidn/plots/plot_eps_per_point.py +++ b/nidn/plots/plot_eps_per_point.py @@ -10,13 +10,17 @@ from ..utils.global_constants import NIDN_FONTSIZE, NIDN_PLOT_COLOR_1 -def plot_eps_per_point(run_cfg, compare_to_material=None, save_path=None, legend=True): +def plot_eps_per_point( + run_cfg, compare_to_material=None, save_path=None, legend=True, file_id=None +): """This function plots the epsilon values of grid points against real materials. Optionally saves it. Args: run_cfg (dict): The run configuration. compare_to_material (str or list): Name(s) of the material to compare with. Available ones are in /materials/data. save_path (str, optional): Folder to save the plot in. Defaults to None, then the plot will not be saved. + legend (bool, optional): Whether to show layer legend + file_id (str, optional): Whether to add a postfix string """ # Create epsilon grid from the model eps, _ = model_to_eps_grid(run_cfg.model, run_cfg) @@ -147,4 +151,8 @@ def plot_eps_per_point(run_cfg, compare_to_material=None, save_path=None, legend fig.autofmt_xdate() if save_path is not None: - plt.savefig(save_path + "/eps_per_points.png", dpi=150) + plt.savefig(save_path + "/eps_per_points" + str(file_id) + ".png", dpi=150) + # fig.clf() + # plt.close(fig) + else: + plt.show() diff --git a/nidn/plots/plot_epsilon_grid.py b/nidn/plots/plot_epsilon_grid.py index 7e34e97..e8ca02c 100644 --- a/nidn/plots/plot_epsilon_grid.py +++ b/nidn/plots/plot_epsilon_grid.py @@ -61,3 +61,5 @@ def plot_epsilon_grid(eps, run_cfg, save_path=None): if save_path is not None: plt.savefig(save_path + "/eps_grid.png", dpi=150) + else: + plt.show() diff --git a/nidn/plots/plot_losses.py b/nidn/plots/plot_losses.py index bf8f90f..b66101b 100644 --- a/nidn/plots/plot_losses.py +++ b/nidn/plots/plot_losses.py @@ -19,3 +19,6 @@ def plot_losses(run_cfg, save_path=None): plt.legend(["L1", "Loss", "Weighted Average Loss"]) if save_path is not None: plt.savefig(save_path + "/losses.png", dpi=150) + else: + plt.show() + diff --git a/nidn/plots/plot_material_grid.py b/nidn/plots/plot_material_grid.py index 56def60..3ec2b3f 100644 --- a/nidn/plots/plot_material_grid.py +++ b/nidn/plots/plot_material_grid.py @@ -114,3 +114,6 @@ def plot_material_grid( if save_path is not None: plt.savefig(save_path + "/material_grid.png", dpi=150) + else: + plt.show() + diff --git a/nidn/plots/plot_model_grid.py b/nidn/plots/plot_model_grid.py index b3f2ba1..e4dbef1 100644 --- a/nidn/plots/plot_model_grid.py +++ b/nidn/plots/plot_model_grid.py @@ -20,7 +20,7 @@ def plot_model_grid(run_cfg, save_path=None): # Here we calculate the absolute value of the permittivity over all frequencies for each grid point eps = torch.mean(eps, dim=3) - eps = torch.sqrt(eps.real ** 2 + eps.imag ** 2) + eps = torch.sqrt(eps.real**2 + eps.imag**2) abs_values = eps.detach().cpu().numpy() @@ -63,3 +63,5 @@ def plot_model_grid(run_cfg, save_path=None): if save_path is not None: plt.savefig(save_path + "/model_grid.png", dpi=150) + else: + plt.show() diff --git a/nidn/plots/plot_model_grid_per_freq.py b/nidn/plots/plot_model_grid_per_freq.py index 290ec13..41041b2 100644 --- a/nidn/plots/plot_model_grid_per_freq.py +++ b/nidn/plots/plot_model_grid_per_freq.py @@ -88,3 +88,5 @@ def plot_model_grid_per_freq(run_cfg, freq_idx=[0, 1, 2, 3], save_path=None): if save_path is not None: plt.savefig(save_path + "/model_grid_per_freq.png", dpi=150) + else: + plt.show() diff --git a/nidn/plots/plot_spectra.py b/nidn/plots/plot_spectra.py index 25b5398..e9fbe24 100644 --- a/nidn/plots/plot_spectra.py +++ b/nidn/plots/plot_spectra.py @@ -79,7 +79,7 @@ def plot_spectra( prod_T_spectrum=None, markers=True, filename=None, - ylim=[[0.0, 1.0],[0.0, 1.0]], + ylim=[[0.0, 1.0], [0.0, 1.0]], ): """Plots the produced RTA spectra together with the target spectra. Optionally saves it. @@ -173,3 +173,7 @@ def plot_spectra( plt.savefig(save_path + "/spectra_comparison.png", dpi=150) else: plt.savefig(save_path + "/" + filename + ".png", dpi=300) + # fig.clf() + # plt.close(fig) + else: + plt.show() diff --git a/nidn/plots/plot_spectrum.py b/nidn/plots/plot_spectrum.py index c910522..18b7fa3 100644 --- a/nidn/plots/plot_spectrum.py +++ b/nidn/plots/plot_spectrum.py @@ -99,7 +99,7 @@ def plot_spectrum( # max(max(A_spectrum), max(T_spectrum), max(R_spectrum)) + 0.1, # ] - fig = plt.figure(figsize=(15, 5), dpi=300) + fig = plt.figure(figsize=(12, 4), dpi=150) fig.patch.set_facecolor("white") fig = _add_plot( @@ -116,7 +116,7 @@ def plot_spectrum( target_frequencies, T_spectrum, ylimits, - (121 if not show_absorption else 132), + (122 if not show_absorption else 132), "Transmittance", markers=markers, ) @@ -138,3 +138,5 @@ def plot_spectrum( plt.savefig(save_path + "/spectrum.png", dpi=150) else: plt.savefig(save_path + "/" + filename + ".png", dpi=300) + else: + plt.show() diff --git a/notebooks/FDTD_RCWA_TMM_Comparison.ipynb b/notebooks/FDTD_RCWA_TMM_Comparison.ipynb index 918464b..0a6684e 100644 --- a/notebooks/FDTD_RCWA_TMM_Comparison.ipynb +++ b/notebooks/FDTD_RCWA_TMM_Comparison.ipynb @@ -183,19 +183,11 @@ " plt.ylim([-0.1,1.1])\n", " plt.savefig(f'../results/{material}.png')" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "140d2626", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3.9.6 ('NIDN')", + "display_name": "Python 3.9.7 ('nidn')", "language": "python", "name": "python3" }, @@ -209,11 +201,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.9.7" }, "vscode": { "interpreter": { - "hash": "f0a9101947082d57fdb1768cbb738b2d65701c74001bd4e9db965265346a5080" + "hash": "1ec5cfae9b828f8ab7e7cdcd8237afffb09b0704a5815a216abf273e6fa91aea" } } }, diff --git a/notebooks/Forward_Model_Simulation_with_FDTD.ipynb b/notebooks/Forward_Model_Simulation_with_FDTD.ipynb index 844db7f..296c062 100644 --- a/notebooks/Forward_Model_Simulation_with_FDTD.ipynb +++ b/notebooks/Forward_Model_Simulation_with_FDTD.ipynb @@ -70,7 +70,7 @@ "# Choose FDTD method, TRCWA other option\n", "cfg.solver = \"FDTD\"\n", "# Set number of time steps in FDTD\n", - "cfg.FDTD_niter = 400\n", + "cfg.FDTD_niter = 600\n", "# Choose pulse type (continuous, hanning or ricker)\n", "cfg.FDTD_pulse_type = 'continuous'\n", "# Choose source type (line or point)\n", @@ -160,7 +160,7 @@ "#Largest wavelength\n", "cfg.physical_wavelength_range[1]=15e-7\n", "# Set number of time steps in FDTD\n", - "cfg.FDTD_niter = 800\n", + "cfg.FDTD_niter = 2400\n", "# Choose pulse type\n", "cfg.FDTD_pulse_type = 'continuous'" ] @@ -217,7 +217,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.9.7 ('nidn')", "language": "python", "name": "python3" }, @@ -231,7 +231,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.9.7" + }, + "vscode": { + "interpreter": { + "hash": "1ec5cfae9b828f8ab7e7cdcd8237afffb09b0704a5815a216abf273e6fa91aea" + } } }, "nbformat": 4, diff --git a/notebooks/Forward_Model_Simulation_with_RCWA.ipynb b/notebooks/Forward_Model_Simulation_with_RCWA.ipynb index a395ea8..5548a20 100644 --- a/notebooks/Forward_Model_Simulation_with_RCWA.ipynb +++ b/notebooks/Forward_Model_Simulation_with_RCWA.ipynb @@ -49,10 +49,10 @@ "source": [ "# Titanium Oxide Uniform\n", "# Set grid specifics\n", - "cfg.Nx = 15\n", - "cfg.Ny = 15\n", + "cfg.Nx = 1\n", + "cfg.Ny = 1\n", "cfg.N_layers = 1\n", - "cfg.N_freq = 32\n", + "cfg.N_freq = 64\n", "cfg.TRCWA_L_grid = [[0.1,0.0],[0.0,0.1]]\n", "cfg.TRCWA_NG = 11\n", "cfg.PER_LAYER_THICKNESS = [1.0]\n", @@ -92,10 +92,7 @@ "outputs": [], "source": [ "# Uniform Titanium oxide\n", - "eps_grid[:,:,0,:] = layer_builder.build_uniform_layer(\"titanium_oxide\")\n", - "eps_grid[:,:,1,:] = layer_builder.build_uniform_layer(\"germanium\")\n", - "eps_grid[:,:,2,:] = layer_builder.build_uniform_layer(\"tantalum_pentoxide\")\n", - "# eps_grid[:,:,0,:] = layer_builder.build_circle_layer(\"tantalum_pentoxide\",\"titanium_oxide\")" + "eps_grid[:,:,0,:] = layer_builder.build_uniform_layer(\"titanium_oxide\")" ] }, { @@ -155,183 +152,11 @@ "[print(f\"{t.item():.8f}\",end=\",\") for t in T]\n", "print(\"]\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c5799f8d", - "metadata": {}, - "outputs": [], - "source": [ - "# Set grid specifics\n", - "cfg.Nx = 1\n", - "cfg.Ny = 1\n", - "cfg.N_layers = 25\n", - "cfg.N_freq = 40\n", - "cfg.TRCWA_L_grid = [[1.,0.0],[0.0,1.]]\n", - "cfg.TRCWA_NG = 11\n", - "\n", - "# Specify your desired range of wavelengths\n", - "cfg.physical_wavelength_range[0] = (1.3)*1e-6\n", - "cfg.physical_wavelength_range[1] = (1.7)*1e-6\n", - "\n", - "# Determine target frequencies (in TRCWA units)\n", - "cfg.target_frequencies = nidn.compute_target_frequencies(\n", - " cfg.physical_wavelength_range[0],\n", - " cfg.physical_wavelength_range[1],\n", - " cfg.N_freq,\n", - " cfg.freq_distribution\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cf04c733", - "metadata": {}, - "outputs": [], - "source": [ - "# Init eps_grid\n", - "eps_grid = torch.zeros(cfg.Nx,cfg.Ny,cfg.N_layers,cfg.N_freq,dtype=torch.cfloat)\n", - "\n", - "layer_builder = nidn.LayerBuilder(cfg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d9a6cdf", - "metadata": {}, - "outputs": [], - "source": [ - "thicknesses = []\n", - "\n", - "n_2 = 2.2\n", - "n_1 = 1.5\n", - "eps_1 = n_1**2\n", - "eps_2 = n_2**2\n", - "\n", - "lam0 = 1.50\n", - "d_1 = lam0/(4*n_1)\n", - "d_2 = lam0/(4*n_2)\n", - "d_defect = lam0/(2*n_1)\n", - "\n", - "# Top DBR\n", - "for i in range(6):\n", - " eps_grid[:,:,2*i,:] = eps_1\n", - " thicknesses.append(d_1)\n", - " eps_grid[:,:,2*i+1,:] = eps_2\n", - " thicknesses.append(d_2)\n", - " \n", - "# Defect \n", - "eps_grid[:,:,12,:] = eps_1\n", - "thicknesses.append(d_defect)\n", - "\n", - "# Bottom DBR\n", - "for i in range(6,12):\n", - " eps_grid[:,:,2*i+1,:] = eps_2\n", - " thicknesses.append(d_2)\n", - " eps_grid[:,:,2*i+2,:] = eps_1\n", - " thicknesses.append(d_1)\n", - "\n", - "thicknesses.reverse()\n", - "cfg.PER_LAYER_THICKNESS = thicknesses\n", - " \n", - "# eps_grid[:,:,0,:] = layer_builder.build_uniform_layer(\"titanium_oxide\")\n", - "# eps_grid[:,:,0,:] = layer_builder.build_squared_layer(\"germanium\",\"tantalum_pentoxide\")\n", - "#eps_grid[:,:,1,:] = layer_builder.build_uniform_layer(\"aluminium_nitride\")\n", - "#eps_grid[:,:,2,:] = layer_builder.build_squared_layer(\"titanium_oxide\",\"germanium\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dbac2e63", - "metadata": {}, - "outputs": [], - "source": [ - "d_1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e9e1e5f6", - "metadata": {}, - "outputs": [], - "source": [ - "d_2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bf467d0d", - "metadata": {}, - "outputs": [], - "source": [ - "d_defect" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2a503788", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot the abs values of the produced grid\n", - "nidn.plot_epsilon_grid(eps_grid,cfg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8fdeb119", - "metadata": {}, - "outputs": [], - "source": [ - "# Compute spectrum for this configuration\n", - "R,T = nidn.compute_spectrum(eps_grid,cfg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "26b1f85f", - "metadata": {}, - "outputs": [], - "source": [ - "nidn.plot_spectrum(cfg,R,T)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4e1c12b3", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"R = [\")\n", - "[print(f\"{r.item():.8f}\",end=\",\") for r in R]\n", - "print(\"]\")\n", - "print(\"T = [\")\n", - "[print(f\"{t.item():.8f}\",end=\",\") for t in T]\n", - "print(\"]\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ff06a683", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.9.7 ('nidn')", "language": "python", "name": "python3" }, @@ -345,7 +170,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.9.7" + }, + "vscode": { + "interpreter": { + "hash": "1ec5cfae9b828f8ab7e7cdcd8237afffb09b0704a5815a216abf273e6fa91aea" + } } }, "nbformat": 4, diff --git a/notebooks/Inverse_Material_Design_with_FDTD.ipynb.ipynb b/notebooks/Inverse_Material_Design_with_FDTD.ipynb.ipynb index 77682d1..ffff9c1 100644 --- a/notebooks/Inverse_Material_Design_with_FDTD.ipynb.ipynb +++ b/notebooks/Inverse_Material_Design_with_FDTD.ipynb.ipynb @@ -29,7 +29,9 @@ "import sys\n", "sys.path.append(\"../\")\n", "\n", - "import nidn" + "import nidn\n", + "import torch\n", + "nidn.set_log_level(\"INFO\")" ] }, { @@ -39,7 +41,7 @@ "source": [ "# Inverse Design of a uniform Titanium Dioxide Layer\n", "\n", - "Here, we define the target spectrum as an already calculated spectrum from a uniform TiO2 layer, and test if NIDN is able to reconstruct the permittivity of the TiO2 layer." + "Here, we define the target spectrum as a spectrum from a uniform TiO2 layer which we compute, and test if NIDN is able to reconstruct the permittivity of the TiO2 layer." ] }, { @@ -55,22 +57,45 @@ "\n", "cfg = nidn.load_default_cfg()\n", "\n", - "# Specify your desired range of wavelengths\n", + "# Specify grid setup\n", + "cfg.Nx = 1 # Set layer size to 1x1 (interpreted as uniform)\n", + "cfg.Ny = 1\n", + "cfg.N_layers = 1 # Choose number of layers\n", "\n", + "# Specify your desired range of wavelengths\n", "cfg.physical_wavelength_range[0] = 3e-7\n", - "cfg.physical_wavelength_range[1] = 1e-6\n", + "cfg.physical_wavelength_range[1] = 9e-7\n", + "cfg.PER_LAYER_THICKNESS = [0.38]\n", + "\n", + "# Let's investigate 16 frequency points\n", + "cfg.N_freq = 16\n", + "\n", + "# use FDTD\n", + "cfg.solver = \"FDTD\"\n", + "\n", + "# Some FDTD specific settings, see docs for details\n", + "cfg.FDTD_min_gridpoints_per_unit_magnitude = 32\n", + "cfg.FDTD_niter = int(800 * cfg.FDTD_min_gridpoints_per_unit_magnitude / 50)\n", + "cfg.FDTD_pulse_type = 'continuous'\n", + "cfg.FDTD_source_type = 'line'\n", "\n", - "# Let's investigate 12 frequency points\n", - "cfg.N_freq = 12\n", + "cfg.target_frequencies = nidn.compute_target_frequencies(\n", + " cfg.physical_wavelength_range[0],\n", + " cfg.physical_wavelength_range[1],\n", + " cfg.N_freq,\n", + " cfg.freq_distribution\n", + ")\n", "\n", - "# Currently, the target spectra is set manually as a list of numbers \n", - "cfg.target_reflectance_spectrum = [0.27891510,0.23644109,0.15938656,0.13485510,0.17970238,0.29539180,0.24678705,0.28984702,0.34120250,0.50414005,0.65206676,0.64914470]\n", - "cfg.target_transmittance_spectrum = [0.69567667,0.68589939,0.66614408,0.64175525,0.61354260,0.56891946,0.51561534,0.41896730,0.21201846,0.00011344,0.00000001,0.00000000]\n", - "# Since R + T + A = 1, we only need to give the reflectance and transmittance (absorptance is implicit)\n", + "# We Compute ground truth\n", + "eps_grid = torch.zeros(cfg.Nx,cfg.Ny,cfg.N_layers,cfg.N_freq,dtype=torch.cfloat)\n", + "layer_builder = nidn.LayerBuilder(cfg)\n", + "eps_grid[:,:,0,:] = layer_builder.build_uniform_layer(\"titanium_oxide\")\n", + "# Compute spectrum for this configuration\n", + "R,T = nidn.compute_spectrum(eps_grid,cfg)\n", + "nidn.plot_spectrum(cfg,R,T,show_absorption=True)\n", "\n", - "nidn.plot_spectrum(cfg,\n", - " cfg.target_reflectance_spectrum,\n", - " cfg.target_transmittance_spectrum)\n", + "cfg.target_reflectance_spectrum = R\n", + "cfg.target_transmittance_spectrum = T\n", "\n", "physical_wls, normalized_freqs = nidn.get_frequency_points(cfg)\n", "print(\"Physical wavelengths are (in meters):\")\n", @@ -94,23 +119,16 @@ "metadata": {}, "outputs": [], "source": [ - "cfg.Nx = 1 # Set layer size to 1x1 (interpreted as uniform)\n", - "cfg.Ny = 1\n", - "cfg.N_layers = 1 # Choose number of layers\n", + "cfg.pop(\"model\",None); # Forget any old model\n", "\n", "# Allowed range of epsilon values\n", "cfg.real_min_eps = 0.0\n", "cfg.real_max_eps = 20.0\n", "cfg.imag_min_eps = 0.0\n", - "cfg.imag_max_eps = 7.0\n", + "cfg.imag_max_eps = 6.0\n", "\n", "# Choose model type, regression or classification\n", - "cfg.type = \"regression\" \n", - "# Set number of training iterations (that is forward model evaluations) to perform\n", - "cfg.iterations = 50 \n", - "\n", - "cfg.FDTD_niter = 400\n", - "cfg.solver = \"FDTD\"" + "cfg.type = \"regression\" " ] }, { @@ -142,6 +160,10 @@ }, "outputs": [], "source": [ + "# Set number of training iterations (that is forward model evaluations) to perform\n", + "# Note that this will be pretty slow for now, 200 iterations lead to a good result\n", + "# but that requires hours\n", + "cfg.iterations = 10 \n", "nidn.run_training(cfg);" ] }, @@ -277,102 +299,11 @@ "nidn.plot_model_grid(cfg)\n", "nidn.plot_eps_per_point(cfg)" ] - }, - { - "cell_type": "markdown", - "id": "b5855a01", - "metadata": {}, - "source": [ - "As can be seen from the plots, the prediction is correct and the loss is even lower." - ] - }, - { - "cell_type": "markdown", - "id": "5a30b861", - "metadata": {}, - "source": [ - "# Classification of three uniform layers of TiO2/GaAs/SiN\n", - "\n", - "This examples shows how NIDN learns the material composition of three uniform layers, with a spectrum previously calculated target spectrum from a simulation with three uniform layers, all 1 um thick, where the first layer is TiO2, the second is GaAs and the third layer is SiN. Note that since the total layer thickness is thicker, the required number of time-steps is also increased, which makes each iteration in the neural network training take more time than for the previous example.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7f7b01f9", - "metadata": {}, - "outputs": [], - "source": [ - "cfg = nidn.load_default_cfg()\n", - "# Set the number of frequencies to simulate for\n", - "cfg.N_freq = 12\n", - "#Number of layers with materials\n", - "cfg.N_layers = 3\n", - "\n", - "# Set layer size to 1x1 (interpreted as uniform)\n", - "cfg.Nx = 1 \n", - "cfg.Ny = 1\n", - " # Forget the old model\n", - "cfg.pop(\"model\",None);\n", - "cfg.type = \"classification\" # Choose type as described above\n", - "# Define the thickness of each layer, in default units\n", - "cfg.PER_LAYER_THICKNESS=[1.0, 1.0, 1.0]\n", - "#Smallest wavelength\n", - "cfg.physical_wavelength_range[0]=3e-7\n", - "#Largest wavelength\n", - "cfg.physical_wavelength_range[1]=15e-7\n", - "#init epsiln values\n", - "#Convert wavelengths to normalized frequencies used by the layer builder\n", - "cfg.target_frequencies = nidn.compute_target_frequencies(\n", - " cfg.physical_wavelength_range[0],\n", - " cfg.physical_wavelength_range[1],\n", - " cfg.N_freq,\n", - " cfg.freq_distribution,\n", - ")\n", - "# Choose FDTD as simulation type\n", - "cfg.solver = \"FDTD\"\n", - "# Number of iterations has to be increased due to a thicker material, thus a further distance for the wave to travel\n", - "cfg.FDTD_niter = 800\n", - "# Choose pulse and source type\n", - "cfg.FDTD_pulse_type = 'continuous'\n", - "cfg.FDTD_source_type = 'line'\n", - "\n", - "# Set target spectrum, generated from a simulation with TiO2/GaAs/SiN triple uniform layer\n", - "cfg.target_transmittance_spectrum = [0.59790906,0.56570349,0.23946883,0.02939799,0.00184458,0.00002115,0.00000011,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000]\n", - "cfg.target_reflectance_spectrum = [0.27799517,0.22808249,0.09394473,0.14923679,0.36340323,0.09872345,0.23317323,0.50220509,0.62269236,0.42524770,0.65769614,0.64963481]\n", - "#Number of forward passes in NIDN\n", - "cfg.iterations = 50" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "666bd083", - "metadata": {}, - "outputs": [], - "source": [ - "# Run the NIDN\n", - "nidn.run_training(cfg);" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f4efc1c8", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot the losses, the best spectrum and the epsilon functions for each layer\n", - "nidn.plot_losses(cfg)\n", - "nidn.plot_spectra(cfg)\n", - "nidn.plot_eps_per_point(cfg)" - ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.9.7 ('nidn')", "language": "python", "name": "python3" }, @@ -386,7 +317,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.9.7" + }, + "vscode": { + "interpreter": { + "hash": "1ec5cfae9b828f8ab7e7cdcd8237afffb09b0704a5815a216abf273e6fa91aea" + } } }, "nbformat": 4, diff --git a/notebooks/Inverse_Material_Design_with_RCWA.ipynb b/notebooks/Inverse_Material_Design_with_RCWA.ipynb index b703aff..87cede0 100644 --- a/notebooks/Inverse_Material_Design_with_RCWA.ipynb +++ b/notebooks/Inverse_Material_Design_with_RCWA.ipynb @@ -106,7 +106,8 @@ "import sys\n", "sys.path.append(\"../\")\n", "\n", - "import nidn" + "import nidn\n", + "nidn.set_log_level(\"INFO\")" ] }, { @@ -134,16 +135,22 @@ "# Load default cfg as starting point\n", "cfg = nidn.load_default_cfg()\n", "\n", + "# TRCWA Settings\n", + "cfg.TRCWA_L_grid = [[0.1,0.0],[0.0,0.1]]\n", + "cfg.TRCWA_NG = 11\n", + "cfg.PER_LAYER_THICKNESS = [1.0]\n", + "\n", "# Specify your desired range of wavelengths\n", "cfg.physical_wavelength_range[0] = 1e-6\n", "cfg.physical_wavelength_range[1] = 1e-5\n", + "cfg.freq_distribution = \"linear\"\n", "\n", "# Let's investigate 32 frequency points\n", "cfg.N_freq = 32\n", "\n", "# Currently, the target spectra is set manually as a list of numbers \n", - "cfg.target_reflectance_spectrum = [0.01990215,0.29430509,0.30827604,0.20568143,0.03479743,0.03237307,0.21794823,0.37803084,0.44122008,0.41114147,0.28422894,0.08763780,0.00471842,0.15989135,0.34718527,0.44319130,0.44568130,0.35408899,0.16817183,0.00585206,0.08819886,0.29369360,0.42720784,0.46166416,0.40164924,0.23886748,0.03722395,0.03982127,0.24579889,0.40972195,0.46816629,0.42871305]\n", - "cfg.target_transmittance_spectrum = [0.80566155,0.68022463,0.65655138,0.79343985,0.96515193,0.96756870,0.78199519,0.62191506,0.55872423,0.58879567,0.71569349,0.91226289,0.99516797,0.84000163,0.65271921,0.55671747,0.55422263,0.64579931,0.83168831,0.99398072,0.91163717,0.70616374,0.57266280,0.53820642,0.59820689,0.76095669,0.96255973,0.95995524,0.75400721,0.59010836,0.53166987,0.57111012]\n", + "cfg.target_reflectance_spectrum = [0.01990215,0.18862374,0.29416452,0.31686834,0.30931051,0.27989507,0.21396754,0.12617596,0.04358692,0.00098217,0.02277351,0.09958942,0.19854391,0.29178026,0.36486594,0.41334028,0.43843368,0.44088565,0.42115803,0.37818036,0.31122202,0.22172910,0.12143359,0.03581180,0.00003041,0.03266791,0.11734958,0.21943795,0.31245563,0.38261433,0.42918729,0.45252977,0.45364987,0.43273948,0.38860548,0.31997456,0.22850632,0.12510194,0.03658242,0.00000571,0.03513296,0.12315892,0.22841223,0.32156572,0.39252449,0.43796520,0.46008328,0.45936085,0.43602135,0.38861368,0.31566885,0.21935769,0.11277557,0.02687095,0.00105129,0.05036984,0.14895267,0.25536387,0.34692635,0.41300526,0.45244442,0.46828458,0.46059485,0.42871305,][::2]\n", + "cfg.target_transmittance_spectrum = [0.80566155,0.80183012,0.68040095,0.63592999,0.65381371,0.71016360,0.78471449,0.87372850,0.95636285,0.99896277,0.97716848,0.90035231,0.80139917,0.70816446,0.63507985,0.58660559,0.56151111,0.55905677,0.57878055,0.62175262,0.68870337,0.77818657,0.87847102,0.96408236,0.99985706,0.96721862,0.88254093,0.78045866,0.68744676,0.61729215,0.57072126,0.54737868,0.54625622,0.56716181,0.61128826,0.67990851,0.77136297,0.87475156,0.96325655,0.99982487,0.96469840,0.87668054,0.77143817,0.67829456,0.60734302,0.56190626,0.53978890,0.54050873,0.56384214,0.61123979,0.68417021,0.78046270,0.88702387,0.97291039,0.99872179,0.94940799,0.85083899,0.74444367,0.65289492,0.58682550,0.54739120,0.53155152,0.53923725,0.57111012,][::2]\n", "# Since R + T + A = 1, we only need to give the reflectance and transmittance (absorptance is implicit)\n", "\n", "nidn.plot_spectrum(cfg,\n", @@ -192,7 +199,7 @@ "source": [ "cfg.Nx = 1 # Set layer size to 1x1 (interpreted as uniform)\n", "cfg.Ny = 1\n", - "# cfg.N_layers = 1 # Choose number of layers\n", + "cfg.N_layers = 1 # Choose number of layers\n", "\n", "# Allowed range of epsilon values\n", "cfg.real_min_eps = 0.0\n", @@ -201,7 +208,7 @@ "cfg.imag_max_eps = 3.0\n", "\n", "cfg.type = \"regression\" # Choose type as described above\n", - "cfg.iterations = 100 # Set number of training iterations (that is forward model evaluations) to perform" + "cfg.iterations = 200 # Set number of training iterations (that is forward model evaluations) to perform" ] }, { @@ -315,7 +322,7 @@ "metadata": {}, "outputs": [], "source": [ - "nidn.plot_eps_per_point(cfg)" + "nidn.plot_eps_per_point(cfg,compare_to_material=\"titanium_oxide\")" ] }, { @@ -366,7 +373,7 @@ "nidn.plot_losses(cfg)\n", "nidn.plot_spectra(cfg)\n", "nidn.plot_model_grid(cfg)\n", - "nidn.plot_eps_per_point(cfg)" + "nidn.plot_eps_per_point(cfg,compare_to_material=\"titanium_oxide\")" ] }, { @@ -421,6 +428,7 @@ "outputs": [], "source": [ "# Allowed range of epsilon values\n", + "cfg.pop(\"model\",None); # Forget the old model\n", "cfg.real_min_eps = 0.0\n", "cfg.real_max_eps = 20.0\n", "imag_min_eps = 0.0\n", @@ -429,9 +437,19 @@ "cfg.Nx = 1 # Set layer size to 16x16 (each of the grid points has its own epsilon now)\n", "cfg.Ny = 1\n", "cfg.eps_oversampling = 1\n", - "cfg.N_layers = 10 # Less layer to keep compute managable\n", + "cfg.N_layers = 3 # Less layer to keep compute managable\n", "cfg.type = \"regression\" # Choose type as described above (for now still regression)\n", - "cfg.iterations = 3000 # Set number of training iterations (that is forward model evaluations) to perform" + "cfg.iterations = 400 # Set number of training iterations (that is forward model evaluations) to perform" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "793a89c8", + "metadata": {}, + "outputs": [], + "source": [ + "nidn.print_cfg(cfg)" ] }, { @@ -459,7 +477,7 @@ "nidn.plot_losses(cfg)\n", "nidn.plot_spectra(cfg)\n", "nidn.plot_model_grid(cfg)\n", - "nidn.plot_eps_per_point(cfg)" + "nidn.plot_eps_per_point(cfg,legend=False)" ] }, { @@ -504,116 +522,13 @@ "nidn.save_run(cfg)\n", "\n", "# You can save all available plots to a single folder using this function\n", - "nidn.save_all_plots(cfg,save_path=\"/results/example/\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c2de9e9b", - "metadata": {}, - "outputs": [], - "source": [ - "# Squared german & tantalum layer\n", - "cfg = nidn.load_default_cfg()\n", - "cfg.N_freq = 20\n", - "cfg.target_reflectance_spectrum = [0.60248210,0.20808528,0.10825184,0.55990793,0.72659247,0.74876763,0.65817925,0.32626005,0.03080333,0.50414092,0.71607931,0.75605811,0.68509433,0.38961000,0.01012443,0.48532436,0.71720245,0.76067772,0.69521557,0.41321222,]\n", - "cfg.target_transmittance_spectrum = [0.38656270,0.77990755,0.88060908,0.43550853,0.27110902,0.24957937,0.33986960,0.67012270,0.96391071,0.49316468,0.28246341,0.24277933,0.31350818,0.60775718,0.98545664,0.51235020,0.28152825,0.23829265,0.30353337,0.58443205,]\n", - "cfg.physical_wavelength_range[0] = 2e-6\n", - "cfg.physical_wavelength_range[1] = 1e-5\n", - "cfg.freq_distribution = \"linear\"\n", - "\n", - "nidn.plot_spectrum(cfg,\n", - " cfg.target_reflectance_spectrum,\n", - " cfg.target_transmittance_spectrum)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "15c5566e", - "metadata": {}, - "outputs": [], - "source": [ - "cfg.pop(\"model\",None); # Forget the old model\n", - "cfg.Nx = 9 # Set layer size to 1x1 (interpreted as uniform)\n", - "cfg.Ny = 9\n", - "cfg.eps_oversampling = 3\n", - "cfg.N_layers = 1 # Choose number of layers\n", - "cfg.type = \"regression\" # Choose type as described above\n", - "cfg.iterations = 5000 # Set number of training iterations (that is forward model evaluations) to perform" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5181f3e4", - "metadata": {}, - "outputs": [], - "source": [ - "nidn.run_training(cfg);" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4d05689b", - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "nidn.plot_losses(cfg)\n", - "nidn.plot_spectra(cfg)\n", - "nidn.plot_model_grid(cfg)\n", - "nidn.plot_eps_per_point(cfg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "22683307", - "metadata": {}, - "outputs": [], - "source": [ - "cfg.pop(\"model\",None); # Forget the old model\n", - "cfg.Nx = 9 # Set layer size to 1x1 (interpreted as uniform)\n", - "cfg.Ny = 9\n", - "cfg.eps_oversampling = 3\n", - "cfg.N_layers = 1 # Choose number of layers\n", - "cfg.type = \"classification\" # Choose type as described above\n", - "cfg.iterations = 5000 # Set number of training iterations (that is forward model evaluations) to perform" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a908be60", - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "nidn.run_training(cfg);" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1bb9d3ac", - "metadata": {}, - "outputs": [], - "source": [ - "nidn.plot_losses(cfg)\n", - "nidn.plot_spectra(cfg)\n", - "nidn.plot_model_grid(cfg)\n", - "nidn.plot_eps_per_point(cfg)" + "nidn.save_all_plots(cfg,save_path=\"../results/example/\")" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.9.7 ('nidn')", "language": "python", "name": "python3" }, @@ -627,7 +542,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.9.7" + }, + "vscode": { + "interpreter": { + "hash": "1ec5cfae9b828f8ab7e7cdcd8237afffb09b0704a5815a216abf273e6fa91aea" + } } }, "nbformat": 4, diff --git a/requirements.txt b/requirements.txt index 75d16aa..8cded16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,9 @@ +dotmap>=1.3.24 +loguru>=0.5.3 matplotlib>=3.3.3 +numpy>=1.20.0 pandas>=1.3.1 -torch==1.9.0 -tqdm>=4.56.0 -loguru>=0.5.3 -dotmap>=1.3.24 \ No newline at end of file +scipy>=1.6.0 +tqdm>=4.56.1 +toml>=0.10.2 +torch>=1.9 \ No newline at end of file diff --git a/setup.py b/setup.py index 607a6bc..122dd88 100644 --- a/setup.py +++ b/setup.py @@ -9,10 +9,10 @@ setup( name="nidn", - version="0.1.0", + version="0.1.1", description="A package for inverse material design of nanostructures using neural networks.", - # long_description=open("README.md").read(), - # long_description_content_type="text/markdown", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", url="https://github.com/esa/nidn", author="ESA Advanced Concepts Team", author_email="pablo.gomez@esa.int",