├── .gitattributes ├── image ├── schematic.png ├── example1_schematic.png └── example6_schematic.png ├── requirements.txt ├── docs └── TORCWA_User_Guide_ver_0.1.0.pdf ├── torcwa ├── __init__.py ├── torch_eig.py └── geometry.py ├── setup.py ├── LICENSE ├── example ├── Materials.py ├── Example3.ipynb ├── Example4.ipynb ├── Materials_data │ └── aSiH.txt ├── Example5.ipynb └── Example0.ipynb ├── .gitignore └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /image/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kch3782/torcwa/HEAD/image/schematic.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | --find-links https://download.pytorch.org/whl/torch_stable.html 2 | torch>=1.10.1 -------------------------------------------------------------------------------- /image/example1_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kch3782/torcwa/HEAD/image/example1_schematic.png -------------------------------------------------------------------------------- /image/example6_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kch3782/torcwa/HEAD/image/example6_schematic.png -------------------------------------------------------------------------------- /docs/TORCWA_User_Guide_ver_0.1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kch3782/torcwa/HEAD/docs/TORCWA_User_Guide_ver_0.1.0.pdf -------------------------------------------------------------------------------- /torcwa/__init__.py: -------------------------------------------------------------------------------- 1 | from .torch_eig import Eig 2 | from .geometry import geometry, rcwa_geo 3 | from .rcwa import rcwa 4 | 5 | __author__ = '''Changhyun Kim''' 6 | __version__ = '0.1.4.2' -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='torcwa', 5 | version='0.1.4.2', 6 | description='GPU-accelerated Fourier modal method with automatic differentiation', 7 | author='Changhyun Kim', 8 | author_email='kch3782@snu.ac.kr', 9 | license='LGPL', 10 | url='https://github.com/kch3782/torcwa', 11 | install_requires=['torch>=1.10.1'], 12 | dependency_links=['https://download.pytorch.org/whl/torch_stable.html'], 13 | packages=find_packages(), 14 | keywords='torcwa', 15 | python_requires='>=3.8', 16 | classifiers=[ 17 | 'Programming Language :: Python :: 3.8', 18 | ] 19 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | TORCWA: GPU-accelerated rigorous coupled-wave analysis with automatic differentiation 5 | Copyright (C) 2022 Changhyun Kim 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this program. If not, see . -------------------------------------------------------------------------------- /torcwa/torch_eig.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | ''' 4 | Pytorch 1.10.1 5 | Complex domain eigen-decomposition with numerical stability 6 | ''' 7 | 8 | class Eig(torch.autograd.Function): 9 | broadening_parameter = 1e-10 10 | 11 | @staticmethod 12 | def forward(ctx,x): 13 | ctx.input = x 14 | eigval, eigvec = torch.linalg.eig(x) 15 | ctx.eigval = eigval.cpu() 16 | ctx.eigvec = eigvec.cpu() 17 | return eigval, eigvec 18 | 19 | @staticmethod 20 | def backward(ctx,grad_eigval,grad_eigvec): 21 | eigval = ctx.eigval.to(grad_eigval) 22 | eigvec = ctx.eigvec.to(grad_eigvec) 23 | 24 | grad_eigval = torch.diag(grad_eigval) 25 | s = eigval.unsqueeze(-2) - eigval.unsqueeze(-1) 26 | 27 | # Lorentzian broadening: get small error but stabilizing the gradient calculation 28 | if Eig.broadening_parameter is not None: 29 | F = torch.conj(s)/(torch.abs(s)**2 + Eig.broadening_parameter) 30 | elif s.dtype == torch.complex64: 31 | F = torch.conj(s)/(torch.abs(s)**2 + 1.4e-45) 32 | elif s.dtype == torch.complex128: 33 | F = torch.conj(s)/(torch.abs(s)**2 + 4.9e-324) 34 | 35 | diag_indices = torch.linspace(0,F.shape[-1]-1,F.shape[-1],dtype=torch.int64) 36 | F[diag_indices,diag_indices] = 0. 37 | XH = torch.transpose(torch.conj(eigvec),-2,-1) 38 | tmp = torch.conj(F) * torch.matmul(XH, grad_eigvec) 39 | 40 | grad = torch.matmul(torch.matmul(torch.inverse(XH), grad_eigval + tmp), XH) 41 | if not torch.is_complex(ctx.input): 42 | grad = torch.real(grad) 43 | 44 | return grad -------------------------------------------------------------------------------- /example/Materials.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from scipy.interpolate import interp1d 4 | 5 | class aSiH(torch.autograd.Function): 6 | @staticmethod 7 | def forward(ctx, wavelength, dl = 0.005): 8 | # open material data 9 | open_name = 'Materials_data/aSiH.txt' 10 | f = open(open_name) 11 | data = f.readlines() 12 | f.close() 13 | nk_data = [] 14 | for i in range(len(data)): 15 | _lamb0, _n, _k = data[i].split() 16 | nk_data.append([float(_lamb0), float(_n), float(_k)]) 17 | nk_data = np.array(nk_data) 18 | 19 | n_interp = interp1d(nk_data[:,0],nk_data[:,1],kind='cubic') 20 | k_interp = interp1d(nk_data[:,0],nk_data[:,2],kind='cubic') 21 | 22 | wavelength_np = wavelength.detach().cpu().numpy() 23 | 24 | if wavelength_np < nk_data[0,0]: 25 | nk_value = nk_data[0,1]+1.j*nk_data[0,2] 26 | elif wavelength_np > nk_data[-1,0]: 27 | nk_value = nk_data[-1,1]+1.j*nk_data[-1,2] 28 | else: 29 | nk_value = n_interp(wavelength_np)+1.j*k_interp(wavelength_np) 30 | 31 | if wavelength_np-dl < nk_data[0,0]: 32 | nk_value_m = nk_data[0,1]+1.j*nk_data[0,2] 33 | elif wavelength_np-dl > nk_data[-1,0]: 34 | nk_value_m = nk_data[-1,1]+1.j*nk_data[-1,2] 35 | else: 36 | nk_value_m = n_interp(wavelength_np-dl)+1.j*k_interp(wavelength_np-dl) 37 | 38 | if wavelength_np+dl < nk_data[0,0]: 39 | nk_value_p = nk_data[0,1]+1.j*nk_data[0,2] 40 | elif wavelength_np+dl > nk_data[-1,0]: 41 | nk_value_p = nk_data[-1,1]+1.j*nk_data[-1,2] 42 | else: 43 | nk_value_p = n_interp(wavelength_np+dl)+1.j*k_interp(wavelength_np+dl) 44 | 45 | ctx.dnk_dl = (nk_value_p - nk_value_m) / (2*dl) 46 | 47 | return torch.tensor(nk_value,dtype=torch.complex128 if ((wavelength.dtype is torch.float64) or\ 48 | (wavelength.dtype is torch.complex128)) else torch.complex64, device=wavelength.device) 49 | 50 | @staticmethod 51 | def backward(ctx, grad_output): 52 | grad = 2*torch.real(torch.conj(grad_output)*ctx.dnk_dl) 53 | return grad -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ -------------------------------------------------------------------------------- /example/Example3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "'''\n", 10 | "TORCWA Example3\n", 11 | "Parametric sweep on rectangular meta-atom\n", 12 | "\n", 13 | "'''\n", 14 | "# Import\n", 15 | "import numpy as np\n", 16 | "import torch\n", 17 | "import scipy.io\n", 18 | "import time\n", 19 | "\n", 20 | "import torcwa\n", 21 | "import Materials\n", 22 | "\n", 23 | "# Hardware\n", 24 | "# If GPU support TF32 tensor core, the matmul operation is faster than FP32 but with less precision.\n", 25 | "# If you need accurate operation, you have to disable the flag below.\n", 26 | "torch.backends.cuda.matmul.allow_tf32 = False\n", 27 | "sim_dtype = torch.complex64\n", 28 | "geo_dtype = torch.float32\n", 29 | "device = torch.device('cpu')\n", 30 | "\n", 31 | "# Simulation environment\n", 32 | "# light\n", 33 | "lamb0 = torch.tensor(532.,dtype=geo_dtype,device=device) # nm\n", 34 | "inc_ang = 0.*(np.pi/180) # radian\n", 35 | "azi_ang = 0.*(np.pi/180) # radian\n", 36 | "\n", 37 | "# material\n", 38 | "substrate_eps = 1.46**2\n", 39 | "silicon_eps = Materials.aSiH.apply(lamb0)**2\n", 40 | "\n", 41 | "# geometry\n", 42 | "L = [300., 300.] # nm / nm\n", 43 | "torcwa.rcwa_geo.dtype = geo_dtype\n", 44 | "torcwa.rcwa_geo.device = device\n", 45 | "torcwa.rcwa_geo.Lx = L[0]\n", 46 | "torcwa.rcwa_geo.Ly = L[1]\n", 47 | "torcwa.rcwa_geo.nx = 300\n", 48 | "torcwa.rcwa_geo.ny = 300\n", 49 | "torcwa.rcwa_geo.grid()\n", 50 | "torcwa.rcwa_geo.edge_sharpness = 1000.\n", 51 | "\n", 52 | "x_axis = torcwa.rcwa_geo.x.cpu()\n", 53 | "y_axis = torcwa.rcwa_geo.y.cpu()\n", 54 | "\n", 55 | "# layers\n", 56 | "layer0_thickness = 300." 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 2, 62 | "metadata": {}, 63 | "outputs": [ 64 | { 65 | "name": "stdout", 66 | "output_type": "stream", 67 | "text": [ 68 | "9.09 % Completed.\n", 69 | "18.18 % Completed.\n", 70 | "27.27 % Completed.\n", 71 | "36.36 % Completed.\n", 72 | "45.45 % Completed.\n", 73 | "54.54 % Completed.\n", 74 | "63.63 % Completed.\n", 75 | "72.72 % Completed.\n", 76 | "81.81 % Completed.\n", 77 | "90.9 % Completed.\n", 78 | "100.0 % Completed.\n", 79 | "Elapsed time: 18939.01 s\n" 80 | ] 81 | } 82 | ], 83 | "source": [ 84 | "# Generate and perform simulation\n", 85 | "order_N = 20\n", 86 | "order = [order_N,order_N]\n", 87 | "Wx = torch.linspace(50.,250.,11,dtype=geo_dtype,device=device)\n", 88 | "Wy = torch.linspace(50.,250.,11,dtype=geo_dtype,device=device)\n", 89 | "\n", 90 | "start_time = time.time()\n", 91 | "txx = torch.zeros((11,11),dtype=sim_dtype,device=device)\n", 92 | "for Wx_ind in range(len(Wx)):\n", 93 | " for Wy_ind in range(len(Wy)):\n", 94 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device)\n", 95 | " sim.add_input_layer(eps=substrate_eps)\n", 96 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 97 | " layer0_geometry = torcwa.rcwa_geo.rectangle(Wx=Wx[Wx_ind],Wy=Wy[Wy_ind],Cx=L[0]/2.,Cy=L[1]/2.)\n", 98 | " layer0_eps = layer0_geometry*silicon_eps + (1.-layer0_geometry)\n", 99 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 100 | " sim.solve_global_smatrix()\n", 101 | " txx[Wx_ind,Wy_ind] = sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0])\n", 102 | " print(str(int((Wx_ind+1)/len(Wx)*10000)/100)+' % Completed.')\n", 103 | "end_time = time.time()\n", 104 | "elapsed_time = end_time - start_time\n", 105 | "print('Elapsed time: '+str(int(elapsed_time*100)/100)+' s')" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": 3, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "# Export spectrum data\n", 115 | "filename = 'Example3_spectrum_data_XeonGold5118_CPUonly_64bit_order_'+str(order_N)+'.mat'\n", 116 | "# filename = 'Example3_spectrum_data_XeonGold5118_RTX3090_64bit_FP32_order_'+str(order_N)+'.mat'\n", 117 | "# filename = 'Example3_spectrum_data_XeonGold5118_RTX3090_64bit_TF32_order_'+str(order_N)+'.mat'\n", 118 | "# filename = 'Example3_spectrum_data_XeonGold5118_RTX3090_128bit_order_'+str(order_N)+'.mat'\n", 119 | "\n", 120 | "ex3_data = {'Wx':Wx.cpu().numpy(),'Wy':Wy.cpu().numpy(),'txx':txx.cpu().numpy(),'elapsed_time':elapsed_time}\n", 121 | "scipy.io.savemat(filename,ex3_data)" 122 | ] 123 | } 124 | ], 125 | "metadata": { 126 | "kernelspec": { 127 | "display_name": "base", 128 | "language": "python", 129 | "name": "python3" 130 | }, 131 | "language_info": { 132 | "codemirror_mode": { 133 | "name": "ipython", 134 | "version": 3 135 | }, 136 | "file_extension": ".py", 137 | "mimetype": "text/x-python", 138 | "name": "python", 139 | "nbconvert_exporter": "python", 140 | "pygments_lexer": "ipython3", 141 | "version": "3.9.7 (default, Sep 16 2021, 16:59:28) [MSC v.1916 64 bit (AMD64)]" 142 | }, 143 | "orig_nbformat": 2, 144 | "vscode": { 145 | "interpreter": { 146 | "hash": "a077222d77dfe082b8f1dd562ad70e458ac2ab76993a0b248ab0476e32e9e8dd" 147 | } 148 | } 149 | }, 150 | "nbformat": 4, 151 | "nbformat_minor": 2 152 | } 153 | -------------------------------------------------------------------------------- /example/Example4.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "'''\n", 10 | "TORCWA Example4\n", 11 | "Gradient calculation of cylindrical meta-atom\n", 12 | "\n", 13 | "'''\n", 14 | "# Import\n", 15 | "import numpy as np\n", 16 | "import torch\n", 17 | "import scipy.io\n", 18 | "\n", 19 | "import torcwa\n", 20 | "\n", 21 | "# Hardware\n", 22 | "# If GPU support TF32 tensor core, the matmul operation is faster than FP32 but with less precision.\n", 23 | "# If you need accurate operation, you have to disable the flag below.\n", 24 | "torch.backends.cuda.matmul.allow_tf32 = False\n", 25 | "sim_dtype = torch.complex128\n", 26 | "geo_dtype = torch.float64\n", 27 | "device = torch.device('cuda')\n", 28 | "\n", 29 | "# Simulation environment\n", 30 | "# light\n", 31 | "lamb0 = torch.tensor(473.,dtype=geo_dtype,device=device) # nm\n", 32 | "inc_ang = 0.*(np.pi/180) # radian\n", 33 | "azi_ang = 0.*(np.pi/180) # radian\n", 34 | "\n", 35 | "# material\n", 36 | "substrate_eps = 1.46**2\n", 37 | "SiN_eps = 2.0709**2\n", 38 | "\n", 39 | "# geometry\n", 40 | "'''\n", 41 | " For accurate calculation of gradient through shape deviation,\n", 42 | " nx and ny should be much finer or edge sharpness should be lower\n", 43 | "'''\n", 44 | "L = [300., 300.] # nm / nm\n", 45 | "torcwa.rcwa_geo.dtype = geo_dtype\n", 46 | "torcwa.rcwa_geo.device = device\n", 47 | "torcwa.rcwa_geo.Lx = L[0]\n", 48 | "torcwa.rcwa_geo.Ly = L[1]\n", 49 | "torcwa.rcwa_geo.nx = 1500\n", 50 | "torcwa.rcwa_geo.ny = 1500\n", 51 | "torcwa.rcwa_geo.grid()\n", 52 | "torcwa.rcwa_geo.edge_sharpness = 500. \n", 53 | "\n", 54 | "x_axis = torcwa.rcwa_geo.x.cpu()\n", 55 | "y_axis = torcwa.rcwa_geo.y.cpu()\n", 56 | "\n", 57 | "# layers\n", 58 | "layer0_thickness = 600." 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 2, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "# Numerical gradient \n", 68 | "# Generate and perform simulation\n", 69 | "order_N = 15\n", 70 | "order = [order_N,order_N]\n", 71 | "sampling = 41\n", 72 | "R = torch.linspace(85.,105.,sampling,dtype=geo_dtype,device=device)\n", 73 | "dR = 0.005\n", 74 | "\n", 75 | "txx = []\n", 76 | "txx_p = []\n", 77 | "txx_m = []\n", 78 | "R_grad_ex = torch.zeros(sampling,dtype=geo_dtype,device=device)\n", 79 | "for R_ind in range(len(R)):\n", 80 | " # center\n", 81 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device)\n", 82 | " sim.add_input_layer(eps=substrate_eps)\n", 83 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 84 | " layer0_geometry = torcwa.rcwa_geo.circle(R=R[R_ind],Cx=L[0]/2.,Cy=L[1]/2.)\n", 85 | " layer0_eps = layer0_geometry*SiN_eps + (1.-layer0_geometry)\n", 86 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 87 | " sim.solve_global_smatrix()\n", 88 | " txx.append(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0]))\n", 89 | "\n", 90 | " # +dR\n", 91 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device)\n", 92 | " sim.add_input_layer(eps=substrate_eps)\n", 93 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 94 | " layer0_geometry = torcwa.rcwa_geo.circle(R=R[R_ind]+dR,Cx=L[0]/2.,Cy=L[1]/2.)\n", 95 | " layer0_eps = layer0_geometry*SiN_eps + (1.-layer0_geometry)\n", 96 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 97 | " sim.solve_global_smatrix()\n", 98 | " txx_p.append(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0]))\n", 99 | "\n", 100 | " # -dR\n", 101 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device)\n", 102 | " sim.add_input_layer(eps=substrate_eps)\n", 103 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 104 | " layer0_geometry = torcwa.rcwa_geo.circle(R=R[R_ind]-dR,Cx=L[0]/2.,Cy=L[1]/2.)\n", 105 | " layer0_eps = layer0_geometry*SiN_eps + (1.-layer0_geometry)\n", 106 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 107 | " sim.solve_global_smatrix()\n", 108 | " txx_m.append(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0]))\n", 109 | "\n", 110 | "txx = torch.cat(txx)\n", 111 | "txx_p = torch.cat(txx_p)\n", 112 | "txx_m = torch.cat(txx_m)\n", 113 | "\n", 114 | "R_grad = (torch.abs(txx_p)**2 - torch.abs(txx_m)**2) / (2*dR)\n", 115 | "\n", 116 | "filename = 'Example4_numerical_gradient_data.mat'\n", 117 | "ex4_data = {'R':R.cpu().numpy(),'txx':txx.cpu().numpy(),'txx_p':txx_p.cpu().numpy(),'txx_m':txx_m.cpu().numpy(),'R_grad':R_grad.cpu().numpy()}\n", 118 | "scipy.io.savemat(filename,ex4_data)" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 3, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "# Exact gradient\n", 128 | "# Generate and perform simulation\n", 129 | "R_grad = torch.zeros(sampling,dtype=geo_dtype,device=device)\n", 130 | "for R_ind in range(len(R)):\n", 131 | " R_now = R[R_ind]\n", 132 | " R_now.requires_grad_(True)\n", 133 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device,stable_eig_grad=False)\n", 134 | " sim.add_input_layer(eps=substrate_eps)\n", 135 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 136 | " layer0_geometry = torcwa.rcwa_geo.circle(R=R_now,Cx=L[0]/2.,Cy=L[1]/2.)\n", 137 | " layer0_eps = layer0_geometry*SiN_eps + (1.-layer0_geometry)\n", 138 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 139 | " sim.solve_global_smatrix()\n", 140 | " Txx = torch.abs(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0]))**2\n", 141 | " Txx.backward()\n", 142 | "\n", 143 | " with torch.no_grad():\n", 144 | " R_grad[R_ind] = R_now.grad\n", 145 | " R_now.grad = None\n", 146 | "\n", 147 | "filename = 'Example4_exact_gradient_data.mat'\n", 148 | "ex4_data = {'R':R.cpu().numpy(),'R_grad':R_grad.cpu().numpy()}\n", 149 | "scipy.io.savemat(filename,ex4_data)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 4, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "# Stabilized gradient\n", 159 | "param_list = [10.**(-10), None]\n", 160 | "\n", 161 | "for pl in param_list:\n", 162 | " torcwa.Eig.broadening_parameter = pl\n", 163 | "\n", 164 | " # Generate and perform simulation\n", 165 | " R_grad = torch.zeros(sampling,dtype=geo_dtype,device=device)\n", 166 | " for R_ind in range(len(R)):\n", 167 | " R_now = R[R_ind]\n", 168 | " R_now.requires_grad_(True)\n", 169 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device,stable_eig_grad=True)\n", 170 | " sim.add_input_layer(eps=substrate_eps)\n", 171 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 172 | " layer0_geometry = torcwa.rcwa_geo.circle(R=R_now,Cx=L[0]/2.,Cy=L[1]/2.)\n", 173 | " layer0_eps = layer0_geometry*SiN_eps + (1.-layer0_geometry)\n", 174 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 175 | " sim.solve_global_smatrix()\n", 176 | " Txx = torch.abs(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0]))**2\n", 177 | " Txx.backward()\n", 178 | "\n", 179 | " with torch.no_grad():\n", 180 | " R_grad[R_ind] = R_now.grad\n", 181 | " R_now.grad = None\n", 182 | "\n", 183 | " filename = 'Example4_stabilized_gradient_data_param_'+str(pl)+'.mat'\n", 184 | " ex4_data = {'R':R.cpu().numpy(),'R_grad':R_grad.cpu().numpy()}\n", 185 | " scipy.io.savemat(filename,ex4_data)\n", 186 | " " 187 | ] 188 | } 189 | ], 190 | "metadata": { 191 | "interpreter": { 192 | "hash": "a077222d77dfe082b8f1dd562ad70e458ac2ab76993a0b248ab0476e32e9e8dd" 193 | }, 194 | "kernelspec": { 195 | "display_name": "Python 3.9.7 ('base')", 196 | "language": "python", 197 | "name": "python3" 198 | }, 199 | "language_info": { 200 | "codemirror_mode": { 201 | "name": "ipython", 202 | "version": 3 203 | }, 204 | "file_extension": ".py", 205 | "mimetype": "text/x-python", 206 | "name": "python", 207 | "nbconvert_exporter": "python", 208 | "pygments_lexer": "ipython3", 209 | "version": "3.9.7" 210 | }, 211 | "orig_nbformat": 4 212 | }, 213 | "nbformat": 4, 214 | "nbformat_minor": 2 215 | } 216 | -------------------------------------------------------------------------------- /torcwa/geometry.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.fft 3 | 4 | class geometry: 5 | def __init__(self, 6 | Lx:float=1., 7 | Ly:float=1., 8 | nx:int=100, 9 | ny:int=100, 10 | edge_sharpness:float=1000.,*, 11 | dtype=torch.float32, 12 | device=torch.device('cuda' if torch.cuda.is_available() else 'cpu'), 13 | ): 14 | 15 | ''' 16 | Geometry 17 | 18 | Parameters 19 | - Lx: x-direction Lattice constant (float) 20 | - Ly: y-direction Lattice constant (float) 21 | - x: x-axis sampling number (int) 22 | - y: y-axis sampling number (int) 23 | - edge_sharpness: sharpness of edge (float) 24 | 25 | Keyword Parameters 26 | - dtype: geometry data type (only torch.complex64 and torch.complex128 are allowed.) 27 | - device: geometry device (only torch.device('cpu') and torch.device('cuda') are allowed.) 28 | 29 | ''' 30 | self.Lx = Lx 31 | self.Ly = Ly 32 | self.nx = nx 33 | self.ny = ny 34 | self.edge_sharpness = edge_sharpness 35 | 36 | self.dtype = dtype 37 | self.device = device 38 | 39 | def grid(self): 40 | ''' 41 | Update grid 42 | ''' 43 | 44 | self.x = (self.Lx/self.nx)*(torch.arange(self.nx,dtype=self.dtype,device=self.device)+0.5) 45 | self.y = (self.Ly/self.ny)*(torch.arange(self.ny,dtype=self.dtype,device=self.device)+0.5) 46 | self.x_grid, self.y_grid = torch.meshgrid(self.x,self.y,indexing='ij') 47 | 48 | def circle(self,R,Cx,Cy): 49 | ''' 50 | R: radius 51 | Cx: x center 52 | Cy: y center 53 | ''' 54 | 55 | self.grid() 56 | level = 1. - torch.sqrt(((self.x_grid-Cx)/R)**2 + ((self.y_grid-Cy)/R)**2) 57 | return torch.sigmoid(self.edge_sharpness*level) 58 | 59 | def ellipse(self,Rx,Ry,Cx,Cy,theta=0.): 60 | ''' 61 | Rx: x direction radius 62 | Ry: y direction radius 63 | Cx: x center 64 | Cy: y center 65 | ''' 66 | 67 | theta = torch.as_tensor(theta,dtype=self.dtype,device=self.device) 68 | 69 | self.grid() 70 | level = 1. - torch.sqrt((((self.x_grid-Cx)*torch.cos(theta)+(self.y_grid-Cy)*torch.sin(theta))/Rx)**2 + ((-(self.x_grid-Cx)*torch.sin(theta)+(self.y_grid-Cy)*torch.cos(theta))/Ry)**2) 71 | return torch.sigmoid(self.edge_sharpness*level) 72 | 73 | def square(self,W,Cx,Cy,theta=0.): 74 | ''' 75 | W: width 76 | Cx: x center 77 | Cy: y center 78 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 79 | ''' 80 | 81 | theta = torch.as_tensor(theta,dtype=self.dtype,device=self.device) 82 | 83 | self.grid() 84 | level = 1. - (torch.maximum(torch.abs(((self.x_grid-Cx)*torch.cos(theta)+(self.y_grid-Cy)*torch.sin(theta))/(W/2.)),torch.abs((-(self.x_grid-Cx)*torch.sin(theta)+(self.y_grid-Cy)*torch.cos(theta))/(W/2.)))) 85 | return torch.sigmoid(self.edge_sharpness*level) 86 | 87 | def rectangle(self,Wx,Wy,Cx,Cy,theta=0.): 88 | ''' 89 | Wx: x width 90 | Wy: y width 91 | Cx: x center 92 | Cy: y center 93 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 94 | ''' 95 | 96 | theta = torch.as_tensor(theta,dtype=self.dtype,device=self.device) 97 | 98 | self.grid() 99 | level = 1. - (torch.maximum(torch.abs(((self.x_grid-Cx)*torch.cos(theta)+(self.y_grid-Cy)*torch.sin(theta))/(Wx/2.)),torch.abs((-(self.x_grid-Cx)*torch.sin(theta)+(self.y_grid-Cy)*torch.cos(theta))/(Wy/2.)))) 100 | return torch.sigmoid(self.edge_sharpness*level) 101 | 102 | def rhombus(self,Wx,Wy,Cx,Cy,theta=0.): 103 | ''' 104 | Wx: x diagonal 105 | Wy: y diagonal 106 | Cx: x center 107 | Cy: y center 108 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 109 | ''' 110 | 111 | theta = torch.as_tensor(theta,dtype=self.dtype,device=self.device) 112 | 113 | self.grid() 114 | level = 1. - (torch.abs(((self.x_grid-Cx)*torch.cos(theta)+(self.y_grid-Cy)*torch.sin(theta))/(Wx/2.)) + torch.abs((-(self.x_grid-Cx)*torch.sin(theta)+(self.y_grid-Cy)*torch.cos(theta))/(Wy/2.))) 115 | return torch.sigmoid(self.edge_sharpness*level) 116 | 117 | def super_ellipse(self,Wx,Wy,Cx,Cy,theta=0.,power=2.): 118 | ''' 119 | Wx: x width 120 | Wy: y width 121 | Cx: x center 122 | Cy: y center 123 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 124 | power: elliptic power 125 | ''' 126 | 127 | theta = torch.as_tensor(theta,dtype=self.dtype,device=self.device) 128 | 129 | self.grid() 130 | level = 1. - (torch.abs(((self.x_grid-Cx)*torch.cos(theta)+(self.y_grid-Cy)*torch.sin(theta))/(Wx/2.))**power + torch.abs((-(self.x_grid-Cx)*torch.sin(theta)+(self.y_grid-Cy)*torch.cos(theta))/(Wy/2.))**power)**(1/power) 131 | return torch.sigmoid(self.edge_sharpness*level) 132 | 133 | def union(self,A,B): 134 | ''' 135 | A U B 136 | ''' 137 | 138 | return torch.maximum(A,B) 139 | 140 | def intersection(self,A,B): 141 | ''' 142 | A n B 143 | ''' 144 | 145 | return torch.minimum(A,B) 146 | 147 | def difference(self,A,B): 148 | ''' 149 | A - B = A n Bc 150 | ''' 151 | 152 | return torch.minimum(A,1.-B) 153 | 154 | 155 | class rcwa_geo: 156 | edge_sharpness = 100. # sharpness of edge 157 | Lx = 1. # x-direction Lattice constant 158 | Ly = 1. # y-direction Lattice constant 159 | nx = 100 # x-axis sampling number 160 | ny = 100 # y-axis sampling number 161 | dtype = torch.float32 162 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 163 | 164 | def __init__(self): 165 | pass 166 | 167 | @classmethod 168 | def grid(cls): 169 | ''' 170 | Update grid 171 | ''' 172 | 173 | cls.x = (cls.Lx/cls.nx)*(torch.arange(cls.nx,dtype=cls.dtype,device=cls.device)+0.5) 174 | cls.y = (cls.Ly/cls.ny)*(torch.arange(cls.ny,dtype=cls.dtype,device=cls.device)+0.5) 175 | cls.x_grid, cls.y_grid = torch.meshgrid(cls.x,cls.y,indexing='ij') 176 | 177 | @classmethod 178 | def circle(cls,R,Cx,Cy): 179 | ''' 180 | R: radius 181 | Cx: x center 182 | Cy: y center 183 | ''' 184 | 185 | cls.grid() 186 | level = 1. - torch.sqrt(((cls.x_grid-Cx)/R)**2 + ((cls.y_grid-Cy)/R)**2) 187 | return torch.sigmoid(cls.edge_sharpness*level) 188 | 189 | @classmethod 190 | def ellipse(cls,Rx,Ry,Cx,Cy,theta=0.): 191 | ''' 192 | Rx: x direction radius 193 | Ry: y direction radius 194 | Cx: x center 195 | Cy: y center 196 | ''' 197 | 198 | theta = torch.as_tensor(theta,dtype=cls.dtype,device=cls.device) 199 | 200 | cls.grid() 201 | level = 1. - torch.sqrt((((cls.x_grid-Cx)*torch.cos(theta)+(cls.y_grid-Cy)*torch.sin(theta))/Rx)**2 + ((-(cls.x_grid-Cx)*torch.sin(theta)+(cls.y_grid-Cy)*torch.cos(theta))/Ry)**2) 202 | return torch.sigmoid(cls.edge_sharpness*level) 203 | 204 | @classmethod 205 | def square(cls,W,Cx,Cy,theta=0.): 206 | ''' 207 | W: width 208 | Cx: x center 209 | Cy: y center 210 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 211 | ''' 212 | 213 | theta = torch.as_tensor(theta,dtype=cls.dtype,device=cls.device) 214 | 215 | cls.grid() 216 | level = 1. - (torch.maximum(torch.abs(((cls.x_grid-Cx)*torch.cos(theta)+(cls.y_grid-Cy)*torch.sin(theta))/(W/2.)),torch.abs((-(cls.x_grid-Cx)*torch.sin(theta)+(cls.y_grid-Cy)*torch.cos(theta))/(W/2.)))) 217 | return torch.sigmoid(cls.edge_sharpness*level) 218 | 219 | @classmethod 220 | def rectangle(cls,Wx,Wy,Cx,Cy,theta=0.): 221 | ''' 222 | Wx: x width 223 | Wy: y width 224 | Cx: x center 225 | Cy: y center 226 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 227 | ''' 228 | 229 | theta = torch.as_tensor(theta,dtype=cls.dtype,device=cls.device) 230 | 231 | cls.grid() 232 | level = 1. - (torch.maximum(torch.abs(((cls.x_grid-Cx)*torch.cos(theta)+(cls.y_grid-Cy)*torch.sin(theta))/(Wx/2.)),torch.abs((-(cls.x_grid-Cx)*torch.sin(theta)+(cls.y_grid-Cy)*torch.cos(theta))/(Wy/2.)))) 233 | return torch.sigmoid(cls.edge_sharpness*level) 234 | 235 | @classmethod 236 | def rhombus(cls,Wx,Wy,Cx,Cy,theta=0.): 237 | ''' 238 | Wx: x diagonal 239 | Wy: y diagonal 240 | Cx: x center 241 | Cy: y center 242 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 243 | ''' 244 | 245 | theta = torch.as_tensor(theta,dtype=cls.dtype,device=cls.device) 246 | 247 | cls.grid() 248 | level = 1. - (torch.abs(((cls.x_grid-Cx)*torch.cos(theta)+(cls.y_grid-Cy)*torch.sin(theta))/(Wx/2.)) + torch.abs((-(cls.x_grid-Cx)*torch.sin(theta)+(cls.y_grid-Cy)*torch.cos(theta))/(Wy/2.))) 249 | return torch.sigmoid(cls.edge_sharpness*level) 250 | 251 | @classmethod 252 | def super_ellipse(cls,Wx,Wy,Cx,Cy,theta=0.,power=2.): 253 | ''' 254 | Wx: x width 255 | Wy: y width 256 | Cx: x center 257 | Cy: y center 258 | theta: rotation angle / center: [Cx, Cy] / axis: z-axis 259 | power: elliptic power 260 | ''' 261 | 262 | theta = torch.as_tensor(theta,dtype=cls.dtype,device=cls.device) 263 | 264 | cls.grid() 265 | level = 1. - (torch.abs(((cls.x_grid-Cx)*torch.cos(theta)+(cls.y_grid-Cy)*torch.sin(theta))/(Wx/2.))**power + torch.abs((-(cls.x_grid-Cx)*torch.sin(theta)+(cls.y_grid-Cy)*torch.cos(theta))/(Wy/2.))**power)**(1/power) 266 | return torch.sigmoid(cls.edge_sharpness*level) 267 | 268 | @classmethod 269 | def union(cls,A,B): 270 | ''' 271 | A U B 272 | ''' 273 | 274 | return torch.maximum(A,B) 275 | 276 | @classmethod 277 | def intersection(cls,A,B): 278 | ''' 279 | A n B 280 | ''' 281 | 282 | return torch.minimum(A,B) 283 | 284 | @classmethod 285 | def difference(cls,A,B): 286 | ''' 287 | A - B = A n Bc 288 | ''' 289 | 290 | return torch.minimum(A,1.-B) 291 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **torcwa-0.1.4.2** 2 | ====== 3 | 4 | * License: LGPL 5 | 6 | * User guide: [Link](./docs/TORCWA_User_Guide_ver_0.1.0.pdf) 7 | 8 |
9 | 10 | Features 11 | -------- 12 | **torcwa** (**torc**h + **rcwa**) is a PyTorch implementation of rigorous coupled-wave analysis (RCWA) 13 | 14 | * **GPU-accelerated** simulation 15 | 16 | * Supporting **automatic differentiation** for optimization 17 | 18 | * Units: Lorentz-Heaviside units 19 | 20 | * Speed of light: 1 21 | 22 | * Permittivity and permeability of vacuum: both 1 23 | 24 | * Notation: exp(-*jωt*) 25 | 26 |
27 | 28 | Citation 29 | -------- 30 | ``` 31 | @article{ 32 | title = {TORCWA: GPU-accelerated Fourier modal method and gradient-based optimization for metasurface design}, 33 | journal = {Computer Physics Communications}, 34 | volume = {282}, 35 | pages = {108552}, 36 | year = {2023}, 37 | doi = {https://doi.org/10.1016/j.cpc.2022.108552}, 38 | author = {Changhyun Kim and Byoungho Lee}, 39 | } 40 | ``` 41 | 42 |
43 | 44 | Installation 45 | ------------ 46 | * Requirements 47 | 48 | * Python version 3.8 or higher 49 | 50 | * PyTorch version 1.10.1 or higher 51 | 52 | * For GPU operation, GPUs that support CUDA operations 53 | 54 | * After installing the above requirement, run the following command at the command prompt. 55 | ``` 56 | $ pip install torcwa 57 | ``` 58 | * If the PyTorch version is lower than the required, it will automatically install PyTorch 1.10.1 or higher, but the CPU-only PyTorch or incompatible version may be installed. Therefore, **before installing using the above command, please install PyTorch version that is compatible with GPU**. 59 | 60 |
61 | 62 | Updated features in 0.1.4 63 | ------------ 64 | 1. For S-parameters and sources, p-pol. and s-pol. notation is also available. 65 | - There may be unexpected bugs. If S-paramter is greatly different when comparing with other simulations, or if there are other bugs, please report on issue tap or contact us. 66 | 67 | 2. When calculating the gradient of eigendecomposition, the default value of the broadening parameter (related to stabilization) is changed to 10^-10. 68 | 69 | 3. Class 'geometry' is added and have grid number and lattice constant as instance variables. 70 | - 'rcwa_geo' uses class variables and class methods, and will be removed in a future version. 71 | 72 | 4. Minor bugs are fixed in version 0.1.4.2 73 | 74 | 75 |
76 | 77 | TORCWA Examples 78 | --------------- 79 | 1. [Example 0](./example/Example0.ipynb): Fresnel equation 80 | 81 | 2. [Example 1](./example/Example1.ipynb): Simulation with rectangular meta-atom 82 | Normal incidence / Parametric sweep on wavelength / View electromagnetic field 83 | 84 | 3. [Example 1-1](./example/Example1-1.ipynb): Simulation with stacked meta-atom 85 | Normal incidence / View electromagnetic field 86 | 87 | 4. [Example 2](./example/Example2.ipynb): Simulation with square meta-atom 88 | Oblique incidence / View electromagnetic field 89 | 90 | 5. [Example 3](./example/Example3.ipynb): Simulation with rectangular meta-atom 91 | Normal incidence / Parametric sweep on geometric parameters 92 | 93 | 6. [Example 4](./example/Example4.ipynb): Gradient calculation of cylindrical meta-atom 94 | Differentiation of transmittance with respect to radius 95 | 96 | 7. [Example 5](./example/Example5.ipynb): Shape optimization 97 | Maximize anisotropy 98 | 99 | 8. [Example 6](./example/Example6.ipynb): Topology optimization 100 | Maximize 1st order diffraction 101 | 102 |
103 | 104 | Simulation - Example 1 105 | ---------------------------- 106 | ![schematic](./image/schematic.png) 107 | ![ex1_schematic](./image/example1_schematic.png) 108 | 109 |
110 | 111 | **1.** Define simulation parameters 112 | ```python 113 | import numpy as np 114 | import torch 115 | from matplotlib import pyplot as plt 116 | import scipy.io 117 | 118 | import torcwa 119 | import Materials 120 | 121 | # Hardware 122 | # If GPU support TF32 tensor core, the matmul operation is faster than FP32 but with less precision. 123 | # If you need accurate operation, you have to disable the flag below. 124 | torch.backends.cuda.matmul.allow_tf32 = False 125 | sim_dtype = torch.complex64 126 | geo_dtype = torch.float32 127 | device = torch.device('cuda') 128 | 129 | # Simulation environment 130 | # light 131 | inc_ang = 0.*(np.pi/180) # radian 132 | azi_ang = 0.*(np.pi/180) # radian 133 | 134 | # material 135 | substrate_eps = 1.46**2 136 | 137 | # geometry 138 | L = [300., 300.] # nm / nm 139 | torcwa.rcwa_geo.Lx = L[0] 140 | torcwa.rcwa_geo.Ly = L[1] 141 | torcwa.rcwa_geo.nx = 300 142 | torcwa.rcwa_geo.ny = 300 143 | torcwa.rcwa_geo.grid() 144 | torcwa.rcwa_geo.edge_sharpness = 1000. 145 | torcwa.rcwa_geo.dtype = geo_dtype 146 | torcwa.rcwa_geo.device = device 147 | z = torch.linspace(-500,1500,501,device=device) 148 | 149 | x_axis = torcwa.rcwa_geo.x.cpu() 150 | y_axis = torcwa.rcwa_geo.y.cpu() 151 | z_axis = z.cpu() 152 | 153 | # layers 154 | layer0_geometry = torcwa.rcwa_geo.rectangle(Wx=180.,Wy=100.,Cx=L[0]/2.,Cy=L[1]/2.) 155 | layer0_thickness = 300. 156 | ``` 157 | 158 | * Settings 159 | 160 | * Only PyTorch is required to run the simulation, but other additional libraries are required for data plotting and saving. (Here, matplotlib and scipy are utilized.) 161 | 162 | * torch.backends.cuda.matmul.allow_tf32 163 | **RTX 3090 or later models** support TF32 core operation for matrix multiplication. This is faster than the conventional computation with less accuracy. It is recommended to set to False for accurate operation. 164 | 165 | * sim_dtype 166 | This is a data type that requires **complex number operation** and is used when declaring simulation. 167 | 168 | * geo_dtype 169 | This is a data type that requires **real number operation** and is used when declaring geometric parameters, wavelength, and incident angles. 170 | 171 | * torcwa.rcwa_geo 172 | If the lattice constant and sampling number are specified, basic geometry such as rectangle and circle and functions such as union and intersection can be used. The generated geometry is expressed as 1 or 0 on the grid. The edge sharpness of the geometry also can be specified. The higher this value, the sharper the edge. 173 | 174 |
175 | 176 | * Variables 177 | * inc_ang: incident angle (*θi* in above image) 178 | * azi_ang: azimuthal angle of incidence (*θa* in above image) 179 | * substrate_eps: permittivity of substrate 180 | * L: Lattice constant ([Tx, Ty] in above image) 181 | * layer0_geometry: rectangle with Wx = 180, Wy = 100 182 | * layer0_thickness: height of structure (h in above image) 183 | 184 |
185 | 186 | **2.** View internal layer geometry 187 | ```python 188 | # View layers 189 | plt.imshow(torch.transpose(layer0_geometry,-2,-1).cpu(),origin='lower',extent=[x_axis[0],x_axis[-1],y_axis[0],y_axis[-1]]) 190 | plt.title('Layer 0') 191 | plt.xlim([0,L[0]]) 192 | plt.xlabel('x (nm)') 193 | plt.ylim([0,L[1]]) 194 | plt.ylabel('y (nm)') 195 | plt.colorbar() 196 | ``` 197 | 198 |
199 | 200 | **3.** Generate and perform simulation (**Only get S-paramters** without electromagnetic field) 201 | ```python 202 | order_N = 15 203 | order = [order_N,order_N] 204 | lamb0 = torch.linspace(400.,700.,61,dtype=geo_dtype,device=device) 205 | 206 | txx = [] 207 | for lamb0_ind in range(len(lamb0)): 208 | lamb0_now = lamb0[lamb0_ind] 209 | # Declare simulation 210 | sim = torcwa.rcwa(freq=1/lamb0_now,order=order,L=L,dtype=sim_dtype,device=device) 211 | # Add input and output layer (This step can be skipped if both layers are free space) 212 | sim.add_input_layer(eps=substrate_eps) 213 | # Set incident angle 214 | sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang) 215 | # Add internal layer 216 | silicon_eps = Materials.aSiH.apply(lamb0_now)**2 217 | layer0_eps = layer0_geometry*silicon_eps + (1.-layer0_geometry) 218 | sim.add_layer(thickness=layer0_thickness,eps=layer0_eps) 219 | # Solve global S-matrix 220 | sim.solve_global_smatrix() 221 | # Get S-parameters 222 | txx.append(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0])) 223 | txx = torch.cat(txx) 224 | ``` 225 | 226 | * Variables 227 | * order: truncated Fourier order [x-direction, y-direction] 228 | * lamb0: wavelength for parametric sweep 229 | 230 |
231 | 232 | * Sequence 233 | 234 | 1. Declare simulation 235 | * freq: Frequency 236 | * order: Truncated Fourier order 237 | * L: Lattice constant 238 | * dtype: Simulation data type 239 | * device: Simulation device 240 | 241 | 2. Add input and output layer (This step can be skipped if both layers are free space) 242 | 243 | 3. Set incident angle 244 | * inc_ang: Incident angle 245 | * azi_ang: Azimuthal angle of incidence 246 | * angle_layer: Reference layer to incident and azimuthal angle (default:'input') 247 | 248 | 4. Add internal layer 249 | 250 | 5. Solve global S-matrix 251 | 252 | 6. Get S-parameters 253 | * orders 254 | * direction (forward/backward) 255 | * port (transmission/reflection) 256 | * polarization (xx/xy/yx/yy) 257 | * ref_order: Reference order to calculate S-paramters 258 | 259 |
260 | 261 | **4.** View spectrum and export data 262 | ```python 263 | plt.plot(lamb0.cpu(),torch.abs(txx).cpu()**2) 264 | plt.title('Spectrum (order: '+str(order_N)+')') 265 | plt.xlabel('Wavelength (nm)') 266 | plt.ylabel('Transmittance (a.u.)') 267 | plt.grid() 268 | 269 | ex1_data = {'lamb0':lamb0.cpu().numpy(),'txx':txx.cpu().numpy()} 270 | scipy.io.savemat('Example1_spectrum_data_order_'+str(order_N)+'.mat',ex1_data) 271 | ``` 272 | 273 |
274 | 275 | **5.** Generate and perform simulation (Get electromagnetic field) 276 | ```python 277 | lamb0 = torch.tensor(532.,dtype=geo_dtype,device=device) # nm 278 | 279 | order_N = 15 280 | order = [order_N,order_N] 281 | sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device) 282 | sim.add_input_layer(eps=substrate_eps) 283 | sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang) 284 | silicon_eps = Materials.aSiH.apply(lamb0)**2 285 | layer0_eps = layer0_geometry*silicon_eps + (1.-layer0_geometry) 286 | sim.add_layer(thickness=layer0_thickness,eps=layer0_eps) 287 | sim.solve_global_smatrix() 288 | # Set light source 289 | sim.source_planewave(amplitude=[1.,0.],direction='forward') 290 | 291 | # Get electromagnetic field 292 | [Ex, Ey, Ez], [Hx, Hy, Hz] = sim.field_xz(torcwa.rcwa_geo.x,z,L[1]/2) 293 | Enorm = torch.sqrt(torch.abs(Ex)**2 + torch.abs(Ey)**2 + torch.abs(Ez)**2) 294 | Hnorm = torch.sqrt(torch.abs(Hx)**2 + torch.abs(Hy)**2 + torch.abs(Hz)**2) 295 | ``` 296 | 297 | * Sequence 298 | 299 | 7. Set light source 300 | * amplitude 301 | * direction (forward/backward) 302 | 303 | 8. Get electromagnetic field 304 | * x, y, z axis or point 305 | 306 |
307 | 308 | **6.** View electromagnetic field and export data 309 | ```python 310 | fig, axes = plt.subplots(figsize=(10,12),nrows=2,ncols=4) 311 | im0 = axes[0,0].imshow(torch.transpose(Enorm,-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 312 | axes[0,0].set(title='E norm',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 313 | im1 = axes[0,1].imshow(torch.transpose(torch.abs(Ex),-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 314 | axes[0,1].set(title='Ex abs',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 315 | im2 = axes[0,2].imshow(torch.transpose(torch.abs(Ey),-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 316 | axes[0,2].set(title='Ey abs',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 317 | im3 = axes[0,3].imshow(torch.transpose(torch.abs(Ez),-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 318 | axes[0,3].set(title='Ez abs',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 319 | im4 = axes[1,0].imshow(torch.transpose(Hnorm,-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 320 | axes[1,0].set(title='H norm',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 321 | im5 = axes[1,1].imshow(torch.transpose(torch.abs(Hx),-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 322 | axes[1,1].set(title='Hx abs',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 323 | im6 = axes[1,2].imshow(torch.transpose(torch.abs(Hy),-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 324 | axes[1,2].set(title='Hy abs',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 325 | im7 = axes[1,3].imshow(torch.transpose(torch.abs(Hz),-2,-1).cpu(),cmap='jet',origin='lower',extent=[x_axis[0],x_axis[-1],z_axis[0],z_axis[-1]]) 326 | axes[1,3].set(title='Hz abs',xlim=(0,L[0]),xlabel='x (nm)',ylim=(z_axis[0],z_axis[-1]),ylabel='z (nm)') 327 | fig.colorbar(im0,ax=axes[0,0]) 328 | fig.colorbar(im1,ax=axes[0,1]) 329 | fig.colorbar(im2,ax=axes[0,2]) 330 | fig.colorbar(im3,ax=axes[0,3]) 331 | fig.colorbar(im4,ax=axes[1,0]) 332 | fig.colorbar(im5,ax=axes[1,1]) 333 | fig.colorbar(im6,ax=axes[1,2]) 334 | fig.colorbar(im7,ax=axes[1,3]) 335 | 336 | ex1_XZ_data = {'x_axis':x_axis.numpy(),'y_axis':y_axis.numpy(),'z_axis':z_axis.numpy(),\ 337 | 'Ex':Ex.cpu().numpy(),'Ey':Ey.cpu().numpy(),'Ez':Ez.cpu().numpy(),'Enorm':Enorm.cpu().numpy(),\ 338 | 'Hx':Hx.cpu().numpy(),'Hy':Hy.cpu().numpy(),'Hz':Hz.cpu().numpy(),'Hnorm':Hnorm.cpu().numpy()} 339 | scipy.io.savemat('Example1_XZ_data.mat',ex1_XZ_data) 340 | ``` 341 | 342 |
343 | 344 | Optimization - Example 6 345 | ------------ 346 | ![ex6_schematic](./image/example6_schematic.png) 347 | 348 | **1.** Define simulation parameters 349 | ```python 350 | import numpy as np 351 | import torch 352 | import scipy.io 353 | from matplotlib import pyplot as plt 354 | import time 355 | 356 | import torcwa 357 | import Materials 358 | 359 | # Hardware 360 | sim_dtype = torch.complex64 361 | geo_dtype = torch.float32 362 | device = torch.device('cuda') 363 | 364 | # Simulation environment 365 | # light 366 | lamb0 = torch.tensor(532.,dtype=geo_dtype,device=device) # nm 367 | inc_ang = 0.*(np.pi/180) # radian 368 | azi_ang = 0.*(np.pi/180) # radian 369 | 370 | # material 371 | substrate_eps = 1.46**2 372 | silicon_eps = Materials.aSiH.apply(lamb0)**2 373 | 374 | # geometry 375 | L = [700., 300.] # nm / nm 376 | torcwa.rcwa_geo.Lx = L[0] 377 | torcwa.rcwa_geo.Ly = L[1] 378 | torcwa.rcwa_geo.nx = 700 379 | torcwa.rcwa_geo.ny = 300 380 | torcwa.rcwa_geo.grid() 381 | torcwa.rcwa_geo.edge_sharpness = 1000. 382 | torcwa.rcwa_geo.dtype = geo_dtype 383 | torcwa.rcwa_geo.device = device 384 | 385 | x_axis = torcwa.rcwa_geo.x.cpu() 386 | y_axis = torcwa.rcwa_geo.y.cpu() 387 | 388 | # layers 389 | layer0_thickness = 300. 390 | ``` 391 | 392 | * Same as simulation example 393 | 394 |
395 | 396 | **2.** Define objective function 397 | ```python 398 | def objective_function(rho): 399 | order = [15,8] 400 | 401 | sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device) 402 | sim.add_input_layer(eps=substrate_eps) 403 | sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang) 404 | layer0_eps = rho*silicon_eps + (1.-rho) 405 | sim.add_layer(thickness=layer0_thickness,eps=layer0_eps) 406 | sim.solve_global_smatrix() 407 | t1xx = sim.S_parameters(orders=[1,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0]) 408 | t1yy = sim.S_parameters(orders=[1,0],direction='forward',port='transmission',polarization='yy',ref_order=[0,0]) 409 | t1xy = sim.S_parameters(orders=[1,0],direction='forward',port='transmission',polarization='xy',ref_order=[0,0]) 410 | t1yx = sim.S_parameters(orders=[1,0],direction='forward',port='transmission',polarization='yx',ref_order=[0,0]) 411 | 412 | T1_sum = torch.abs(t1xx)**2 + torch.abs(t1yy)**2 + torch.abs(t1xy)**2 + torch.abs(t1yx)**2 413 | return T1_sum 414 | ``` 415 | 416 | * Objective function should return single scalar value 417 | 418 |
419 | 420 | **3.** Define hyperparameters and initialize 421 | ```python 422 | gar_initial = 0.02 423 | beta1 = 0.9 424 | beta2 = 0.999 425 | epsilon = 1.e-8 426 | iter_max = 800 427 | beta = np.exp(np.arange(start=0,stop=iter_max)*np.log(1000)/iter_max) 428 | gar = gar_initial * 0.5*(1+np.cos(np.arange(start=0,stop=iter_max)*np.pi/iter_max)) 429 | 430 | # blur kernel 431 | blur_radius = 20. 432 | dx, dy = L[0]/torcwa.rcwa_geo.nx, L[1]/torcwa.rcwa_geo.ny 433 | x_kernel_axis = (torch.arange(torcwa.rcwa_geo.nx,dtype=geo_dtype,device=device)-(torcwa.rcwa_geo.nx-1)/2)*dx 434 | y_kernel_axis = (torch.arange(torcwa.rcwa_geo.ny,dtype=geo_dtype,device=device)-(torcwa.rcwa_geo.ny-1)/2)*dy 435 | x_kernel_grid, y_kernel_grid = torch.meshgrid(x_kernel_axis,y_kernel_axis,indexing='ij') 436 | g = torch.exp(-(x_kernel_grid**2+y_kernel_grid**2)/blur_radius**2) 437 | g = g/torch.sum(g) 438 | g_fft = torch.fft.fftshift(torch.fft.fft2(torch.fft.ifftshift(g))) 439 | 440 | torch.manual_seed(0) 441 | rho = torch.rand((torcwa.rcwa_geo.nx,torcwa.rcwa_geo.ny),dtype=geo_dtype,device=device) 442 | rho = (rho + torch.fliplr(rho))/2 443 | rho_fft = torch.fft.fftshift(torch.fft.fft2(torch.fft.ifftshift(rho))) 444 | rho = torch.real(torch.fft.fftshift(torch.fft.ifft2(torch.fft.ifftshift(rho_fft*g_fft)))) 445 | momentum = torch.zeros_like(rho) 446 | velocity = torch.zeros_like(rho) 447 | 448 | rho_history = [] 449 | FoM_history = [] 450 | ``` 451 | 452 | * PyTorch built-in optimization tool can be utilized instead. 453 | 454 | * Define blurring kernel for fabrication feasibility of pattern 455 | 456 | * 'rho' is pattern to optimize 457 | 458 | * Hyperparameters 459 | * gar_initial: Initial learning rate 460 | * beta1: Momentum coefficients in ADAM optimizer 461 | * beta2: Velocity coefficients in ADAM optimizer 462 | * epsilon: Parameter for preventing division by zero 463 | * iter_max: Maximum number of iteration 464 | * beta: Binarize coefficient of pattern at each iteration 465 | * gar: Learning rate at each iteration 466 | 467 |
468 | 469 | **4.** Perform optimization 470 | ```python 471 | start_time = time.time() 472 | for it in range(0,iter_max): 473 | rho.requires_grad_(True) 474 | rho_fft = torch.fft.fftshift(torch.fft.fft2(torch.fft.ifftshift(rho))) 475 | rho_bar = torch.real(torch.fft.fftshift(torch.fft.ifft2(torch.fft.ifftshift(rho_fft*g_fft)))) 476 | rho_tilda = 1/2 + torch.tanh(2*beta[it]*rho_bar-beta[it])/(2*np.math.tanh(beta[it])) 477 | 478 | FoM = objective_function(rho_tilda) 479 | FoM.backward() 480 | 481 | with torch.no_grad(): 482 | rho_gradient = rho.grad 483 | rho.grad = None 484 | 485 | rho_history.append(rho_tilda.detach().cpu().numpy()) 486 | FoM = float(FoM.detach().cpu().numpy()) 487 | FoM_history.append(FoM) 488 | 489 | momentum = (beta1*momentum + (1-beta1)*rho_gradient) 490 | velocity = (beta2*velocity + (1-beta2)*(rho_gradient**2)) 491 | rho += gar[it]*(momentum / (1-beta1**(it+1))) / torch.sqrt((velocity / (1-beta2**(it+1))) + epsilon) 492 | rho[rho>1] = 1 493 | rho[rho<0] = 0 494 | rho = (rho + torch.fliplr(rho))/2 495 | 496 | end_time = time.time() 497 | elapsed_time = end_time - start_time 498 | print('Iteration:',it,'/ FoM:',int(FoM*10000)/10000,'/ Elapsed time:',str(int(elapsed_time))+' s') 499 | ``` 500 | 501 | * Sequence 502 | 503 | 1. Declare 'requires_grad_(True)' for parameters to optimize 504 | 505 | 2. After some manipulation of the parameters, the FoM is derived by substituting it into the objective function. 506 | 507 | 3. Execute 'FoM.backward()' to calculate gradient 508 | 509 | 4. Gradient is obtained using 'rho.grad'. 510 | 511 | 5. Update the parameters according to the optimization algorithm. 512 | 513 |
514 | 515 | Acknowledgements 516 | ---------------- 517 | This work was supported by the National Research Foundation of Korea (NRF) grant funded by the Korea government (MSIT) (No. 2020R1A2B5B02002730) and Samsung Electronics Co., Ltd (IO201214-08164-01). -------------------------------------------------------------------------------- /example/Materials_data/aSiH.txt: -------------------------------------------------------------------------------- 1 | 192 1.358465 2.375775 2 | 193 1.375272 2.386817 3 | 194 1.391996 2.397757 4 | 195 1.408656 2.408625 5 | 196 1.425274 2.419451 6 | 197 1.441878 2.430259 7 | 198 1.4585 2.441069 8 | 199 1.475176 2.451895 9 | 200 1.491943 2.462744 10 | 201 1.508842 2.47362 11 | 202 1.525912 2.484514 12 | 203 1.543195 2.495415 13 | 204 1.560729 2.506302 14 | 205 1.57855 2.517146 15 | 206 1.596691 2.527911 16 | 207 1.615178 2.538553 17 | 208 1.634031 2.549025 18 | 209 1.653263 2.55927 19 | 210 1.672875 2.569229 20 | 211 1.692861 2.578839 21 | 212 1.713199 2.588037 22 | 213 1.73386 2.59676 23 | 214 1.754798 2.604948 24 | 215 1.775956 2.612546 25 | 216 1.797267 2.619508 26 | 217 1.818651 2.625798 27 | 218 1.840019 2.631394 28 | 219 1.861277 2.636288 29 | 220 1.882326 2.64049 30 | 221 1.903066 2.644026 31 | 222 1.923403 2.646941 32 | 223 1.943247 2.649299 33 | 224 1.962518 2.651177 34 | 225 1.981153 2.65267 35 | 226 1.999101 2.653879 36 | 227 2.016331 2.654918 37 | 228 2.03283 2.655901 38 | 229 2.048605 2.656944 39 | 230 2.063681 2.65816 40 | 231 2.0781 2.659655 41 | 232 2.091917 2.661525 42 | 233 2.105203 2.663858 43 | 234 2.118037 2.666724 44 | 235 2.130505 2.670185 45 | 236 2.142699 2.674286 46 | 237 2.154711 2.679059 47 | 238 2.166638 2.684524 48 | 239 2.178569 2.690689 49 | 240 2.190594 2.697549 50 | 241 2.202798 2.705094 51 | 242 2.215261 2.713302 52 | 243 2.228056 2.722146 53 | 244 2.241254 2.731592 54 | 245 2.254915 2.741603 55 | 246 2.269098 2.752138 56 | 247 2.283853 2.763153 57 | 248 2.299228 2.774601 58 | 249 2.315264 2.786434 59 | 250 2.331997 2.798605 60 | 251 2.349461 2.811064 61 | 252 2.367685 2.823762 62 | 253 2.386694 2.836648 63 | 254 2.406512 2.849671 64 | 255 2.427158 2.862783 65 | 256 2.448649 2.875933 66 | 257 2.471002 2.889071 67 | 258 2.494228 2.902144 68 | 259 2.518338 2.915103 69 | 260 2.543342 2.927897 70 | 261 2.569246 2.940473 71 | 262 2.596054 2.952778 72 | 263 2.623769 2.964759 73 | 264 2.652393 2.976362 74 | 265 2.681922 2.987532 75 | 266 2.712353 2.998213 76 | 267 2.74368 3.008347 77 | 268 2.775891 3.017875 78 | 269 2.808974 3.02674 79 | 270 2.842913 3.03488 80 | 271 2.877687 3.042234 81 | 272 2.913272 3.04874 82 | 273 2.949639 3.054337 83 | 274 2.986754 3.058961 84 | 275 3.024579 3.062551 85 | 276 3.063071 3.065045 86 | 277 3.102178 3.066381 87 | 278 3.141845 3.066503 88 | 279 3.182012 3.065351 89 | 280 3.222609 3.062874 90 | 281 3.263562 3.059021 91 | 282 3.304791 3.053747 92 | 283 3.346209 3.047013 93 | 284 3.387724 3.038785 94 | 285 3.429239 3.029038 95 | 286 3.47065 3.017753 96 | 287 3.511853 3.004922 97 | 288 3.552738 2.990547 98 | 289 3.593194 2.974639 99 | 290 3.63311 2.957222 100 | 291 3.672375 2.938331 101 | 292 3.710881 2.918011 102 | 293 3.748522 2.896321 103 | 294 3.7852 2.87333 104 | 295 3.820823 2.84912 105 | 296 3.855307 2.823781 106 | 297 3.888577 2.797411 107 | 298 3.920573 2.770121 108 | 299 3.951245 2.742023 109 | 300 3.980555 2.713235 110 | 301 4.008481 2.68388 111 | 302 4.035015 2.654079 112 | 303 4.060163 2.623954 113 | 304 4.083945 2.593622 114 | 305 4.106394 2.563198 115 | 306 4.127556 2.532786 116 | 307 4.147489 2.502487 117 | 308 4.166259 2.472387 118 | 309 4.183943 2.442564 119 | 310 4.200623 2.413085 120 | 311 4.216386 2.384003 121 | 312 4.231324 2.355358 122 | 313 4.245528 2.327179 123 | 314 4.259092 2.299479 124 | 315 4.272104 2.272263 125 | 316 4.284652 2.245521 126 | 317 4.296816 2.219234 127 | 318 4.308672 2.193374 128 | 319 4.320287 2.167901 129 | 320 4.331722 2.142771 130 | 321 4.343026 2.117934 131 | 322 4.354241 2.093332 132 | 323 4.365399 2.068908 133 | 324 4.376521 2.0446 134 | 325 4.38762 2.020347 135 | 326 4.398698 1.996088 136 | 327 4.409749 1.971764 137 | 328 4.420757 1.94732 138 | 329 4.431702 1.922704 139 | 330 4.442553 1.89787 140 | 331 4.453274 1.872775 141 | 332 4.463826 1.847386 142 | 333 4.474162 1.821674 143 | 334 4.484234 1.795617 144 | 335 4.493993 1.769203 145 | 336 4.503387 1.742423 146 | 337 4.512363 1.715278 147 | 338 4.520871 1.687775 148 | 339 4.52886 1.659928 149 | 340 4.536283 1.631757 150 | 341 4.543096 1.603288 151 | 342 4.549257 1.574551 152 | 343 4.554728 1.545582 153 | 344 4.559478 1.51642 154 | 345 4.563478 1.487108 155 | 346 4.566704 1.45769 156 | 347 4.569139 1.428213 157 | 348 4.570771 1.398727 158 | 349 4.571589 1.36928 159 | 350 4.571591 1.339922 160 | 351 4.570779 1.3107 161 | 352 4.569159 1.281664 162 | 353 4.56674 1.252859 163 | 354 4.563537 1.224329 164 | 355 4.559567 1.196119 165 | 356 4.554851 1.168269 166 | 357 4.549413 1.140816 167 | 358 4.543278 1.113796 168 | 359 4.536475 1.087241 169 | 360 4.529034 1.061183 170 | 361 4.520987 1.035646 171 | 362 4.512365 1.010657 172 | 363 4.503204 0.986235 173 | 364 4.493536 0.9624 174 | 365 4.483397 0.939168 175 | 366 4.472822 0.916552 176 | 367 4.461844 0.894564 177 | 368 4.4505 0.873211 178 | 369 4.438822 0.852502 179 | 370 4.426845 0.832439 180 | 371 4.414603 0.813026 181 | 372 4.402128 0.794264 182 | 373 4.389452 0.776152 183 | 374 4.376608 0.758688 184 | 375 4.363627 0.741867 185 | 376 4.350539 0.725686 186 | 377 4.337376 0.710137 187 | 378 4.324168 0.695214 188 | 379 4.310946 0.680907 189 | 380 4.297743 0.667208 190 | 381 4.2846 0.654104 191 | 382 4.271579 0.641558 192 | 383 4.258668 0.629489 193 | 384 4.245848 0.617892 194 | 385 4.233121 0.606759 195 | 386 4.220493 0.596085 196 | 387 4.207976 0.585859 197 | 388 4.195578 0.576074 198 | 389 4.183311 0.56672 199 | 390 4.171186 0.557785 200 | 391 4.159214 0.549259 201 | 392 4.147405 0.54113 202 | 393 4.135771 0.533386 203 | 394 4.124321 0.526016 204 | 395 4.113065 0.519005 205 | 396 4.102012 0.512341 206 | 397 4.091172 0.506011 207 | 398 4.080553 0.5 208 | 399 4.070161 0.494294 209 | 400 4.060006 0.488879 210 | 401 4.050093 0.483739 211 | 402 4.040429 0.47886 212 | 403 4.031019 0.474226 213 | 404 4.021867 0.469822 214 | 405 4.012978 0.465631 215 | 406 4.004354 0.461638 216 | 407 3.995999 0.457826 217 | 408 3.987913 0.454179 218 | 409 3.980098 0.450681 219 | 410 3.972553 0.447315 220 | 411 3.965278 0.444065 221 | 412 3.95827 0.440914 222 | 413 3.951527 0.437847 223 | 414 3.945045 0.434848 224 | 415 3.938818 0.431901 225 | 416 3.932842 0.428992 226 | 417 3.92711 0.426105 227 | 418 3.921615 0.423226 228 | 419 3.916348 0.420342 229 | 420 3.911299 0.417441 230 | 421 3.90646 0.414509 231 | 422 3.90182 0.411536 232 | 423 3.897367 0.408512 233 | 424 3.89309 0.405426 234 | 425 3.888976 0.402272 235 | 426 3.885014 0.39904 236 | 427 3.88119 0.395726 237 | 428 3.877491 0.392323 238 | 429 3.873904 0.388827 239 | 430 3.870415 0.385236 240 | 431 3.867013 0.381547 241 | 432 3.863683 0.377758 242 | 433 3.860412 0.373871 243 | 434 3.85719 0.369886 244 | 435 3.854003 0.365805 245 | 436 3.850841 0.36163 246 | 437 3.847692 0.357365 247 | 438 3.844547 0.353014 248 | 439 3.841396 0.348582 249 | 440 3.838229 0.344074 250 | 441 3.835039 0.339496 251 | 442 3.831818 0.334855 252 | 443 3.828559 0.330156 253 | 444 3.825258 0.325408 254 | 445 3.821908 0.320616 255 | 446 3.818504 0.315789 256 | 447 3.815044 0.310933 257 | 448 3.811524 0.306055 258 | 449 3.807942 0.301164 259 | 450 3.804296 0.296265 260 | 451 3.800586 0.291367 261 | 452 3.796809 0.286474 262 | 453 3.792967 0.281595 263 | 454 3.789059 0.276736 264 | 455 3.785087 0.271901 265 | 456 3.781052 0.267098 266 | 457 3.776955 0.262331 267 | 458 3.772798 0.257605 268 | 459 3.768584 0.252926 269 | 460 3.764315 0.248297 270 | 461 3.759993 0.243722 271 | 462 3.755622 0.239206 272 | 463 3.751204 0.234751 273 | 464 3.746742 0.230361 274 | 465 3.74224 0.226038 275 | 466 3.737701 0.221785 276 | 467 3.733128 0.217605 277 | 468 3.728525 0.213498 278 | 469 3.723894 0.209466 279 | 470 3.719239 0.205512 280 | 471 3.714564 0.201635 281 | 472 3.709871 0.197838 282 | 473 3.705164 0.19412 283 | 474 3.700446 0.190483 284 | 475 3.695721 0.186926 285 | 476 3.690991 0.183449 286 | 477 3.686259 0.180054 287 | 478 3.681529 0.176739 288 | 479 3.676803 0.173504 289 | 480 3.672084 0.170349 290 | 481 3.667376 0.167274 291 | 482 3.66268 0.164278 292 | 483 3.658 0.16136 293 | 484 3.65334 0.158519 294 | 485 3.648701 0.155755 295 | 486 3.644087 0.153066 296 | 487 3.639502 0.150453 297 | 488 3.634949 0.147912 298 | 489 3.630437 0.145445 299 | 490 3.625976 0.143038 300 | 491 3.621557 0.140678 301 | 492 3.617175 0.138364 302 | 493 3.612826 0.136096 303 | 494 3.60851 0.133873 304 | 495 3.604226 0.131694 305 | 496 3.599972 0.129559 306 | 497 3.59575 0.127468 307 | 498 3.591558 0.125419 308 | 499 3.587396 0.123412 309 | 500 3.583264 0.121446 310 | 501 3.579163 0.11952 311 | 502 3.575091 0.117633 312 | 503 3.57105 0.115786 313 | 504 3.567039 0.113976 314 | 505 3.563057 0.112204 315 | 506 3.559105 0.110468 316 | 507 3.555184 0.108768 317 | 508 3.551292 0.107103 318 | 509 3.54743 0.105472 319 | 510 3.543597 0.103875 320 | 511 3.539795 0.10231 321 | 512 3.536022 0.100778 322 | 513 3.532279 0.099277 323 | 514 3.528565 0.097806 324 | 515 3.52488 0.096366 325 | 516 3.521225 0.094955 326 | 517 3.517599 0.093572 327 | 518 3.514002 0.092218 328 | 519 3.510434 0.09089 329 | 520 3.506895 0.08959 330 | 521 3.503384 0.088315 331 | 522 3.499902 0.087066 332 | 523 3.496448 0.085842 333 | 524 3.493022 0.084642 334 | 525 3.489625 0.083466 335 | 526 3.486254 0.082313 336 | 527 3.482912 0.081183 337 | 528 3.479597 0.080075 338 | 529 3.476309 0.078989 339 | 530 3.473048 0.077923 340 | 531 3.469814 0.076879 341 | 532 3.466607 0.075854 342 | 533 3.463425 0.074849 343 | 534 3.460271 0.073864 344 | 535 3.457142 0.072897 345 | 536 3.454038 0.071948 346 | 537 3.45096 0.071018 347 | 538 3.447908 0.070104 348 | 539 3.44488 0.069208 349 | 540 3.441878 0.068329 350 | 541 3.4389 0.067466 351 | 542 3.435946 0.066619 352 | 543 3.433017 0.065787 353 | 544 3.430111 0.064971 354 | 545 3.42723 0.064169 355 | 546 3.424371 0.063382 356 | 547 3.421536 0.06261 357 | 548 3.418724 0.061851 358 | 549 3.415935 0.061106 359 | 550 3.413169 0.060374 360 | 551 3.410424 0.059655 361 | 552 3.407702 0.058948 362 | 553 3.405002 0.058254 363 | 554 3.402324 0.057572 364 | 555 3.399667 0.056902 365 | 556 3.397031 0.056244 366 | 557 3.394416 0.055597 367 | 558 3.391823 0.054961 368 | 559 3.389249 0.054336 369 | 560 3.386697 0.053722 370 | 561 3.384164 0.053117 371 | 562 3.381651 0.052524 372 | 563 3.379158 0.05194 373 | 564 3.376685 0.051365 374 | 565 3.374232 0.050801 375 | 566 3.371797 0.050245 376 | 567 3.369381 0.049699 377 | 568 3.366984 0.049162 378 | 569 3.364606 0.048633 379 | 570 3.362246 0.048113 380 | 571 3.359904 0.047601 381 | 572 3.35758 0.047098 382 | 573 3.355274 0.046603 383 | 574 3.352986 0.046115 384 | 575 3.350715 0.045636 385 | 576 3.348461 0.045163 386 | 577 3.346225 0.044699 387 | 578 3.344005 0.044241 388 | 579 3.341802 0.043791 389 | 580 3.339616 0.043347 390 | 581 3.337446 0.042911 391 | 582 3.335292 0.042481 392 | 583 3.333154 0.042057 393 | 584 3.331032 0.041641 394 | 585 3.328926 0.04123 395 | 586 3.326835 0.040826 396 | 587 3.32476 0.040427 397 | 588 3.3227 0.040035 398 | 589 3.320655 0.039648 399 | 590 3.318624 0.039268 400 | 591 3.316609 0.038893 401 | 592 3.314608 0.038523 402 | 593 3.312622 0.038159 403 | 594 3.31065 0.0378 404 | 595 3.308692 0.037446 405 | 596 3.306748 0.037097 406 | 597 3.304818 0.036754 407 | 598 3.302901 0.036415 408 | 599 3.300998 0.036081 409 | 600 3.299109 0.035752 410 | 601 3.297233 0.035428 411 | 602 3.29537 0.035108 412 | 603 3.29352 0.034792 413 | 604 3.291683 0.034482 414 | 605 3.289859 0.034175 415 | 606 3.288047 0.033873 416 | 607 3.286248 0.033574 417 | 608 3.284461 0.03328 418 | 609 3.282686 0.03299 419 | 610 3.280924 0.032704 420 | 611 3.279174 0.032422 421 | 612 3.277435 0.032144 422 | 613 3.275708 0.031869 423 | 614 3.273993 0.031598 424 | 615 3.27229 0.031331 425 | 616 3.270598 0.031067 426 | 617 3.268917 0.030807 427 | 618 3.267248 0.03055 428 | 619 3.265589 0.030297 429 | 620 3.263942 0.030047 430 | 621 3.262305 0.0298 431 | 622 3.260679 0.029557 432 | 623 3.259064 0.029316 433 | 624 3.25746 0.029079 434 | 625 3.255865 0.028845 435 | 626 3.254282 0.028614 436 | 627 3.252708 0.028386 437 | 628 3.251145 0.028161 438 | 629 3.249592 0.027938 439 | 630 3.248048 0.027719 440 | 631 3.246515 0.027502 441 | 632 3.244991 0.027288 442 | 633 3.243477 0.027077 443 | 634 3.241973 0.026868 444 | 635 3.240478 0.026663 445 | 636 3.238992 0.026459 446 | 637 3.237516 0.026258 447 | 638 3.236049 0.02606 448 | 639 3.234591 0.025864 449 | 640 3.233143 0.025671 450 | 641 3.231703 0.02548 451 | 642 3.230272 0.025291 452 | 643 3.22885 0.025104 453 | 644 3.227437 0.02492 454 | 645 3.226032 0.024738 455 | 646 3.224636 0.024559 456 | 647 3.223249 0.024381 457 | 648 3.221869 0.024206 458 | 649 3.220499 0.024033 459 | 650 3.219136 0.023861 460 | 651 3.217782 0.023692 461 | 652 3.216436 0.023525 462 | 653 3.215098 0.02336 463 | 654 3.213767 0.023197 464 | 655 3.212445 0.023036 465 | 656 3.211131 0.022877 466 | 657 3.209824 0.022719 467 | 658 3.208525 0.022564 468 | 659 3.207233 0.02241 469 | 660 3.20595 0.022258 470 | 661 3.204673 0.022108 471 | 662 3.203404 0.02196 472 | 663 3.202143 0.021813 473 | 664 3.200889 0.021668 474 | 665 3.199641 0.021525 475 | 666 3.198402 0.021384 476 | 667 3.197169 0.021244 477 | 668 3.195943 0.021106 478 | 669 3.194725 0.020969 479 | 670 3.193513 0.020834 480 | 671 3.192308 0.0207 481 | 672 3.19111 0.020568 482 | 673 3.189918 0.020438 483 | 674 3.188734 0.020309 484 | 675 3.187556 0.020181 485 | 676 3.186384 0.020055 486 | 677 3.185219 0.01993 487 | 678 3.184061 0.019807 488 | 679 3.182909 0.019685 489 | 680 3.181763 0.019565 490 | 681 3.180623 0.019446 491 | 682 3.17949 0.019328 492 | 683 3.178363 0.019212 493 | 684 3.177242 0.019097 494 | 685 3.176128 0.018983 495 | 686 3.175019 0.01887 496 | 687 3.173916 0.018759 497 | 688 3.17282 0.018649 498 | 689 3.171729 0.01854 499 | 690 3.170644 0.018433 500 | 691 3.169565 0.018326 501 | 692 3.168491 0.018221 502 | 693 3.167423 0.018117 503 | 694 3.166362 0.018014 504 | 695 3.165305 0.017913 505 | 696 3.164254 0.017812 506 | 697 3.163209 0.017713 507 | 698 3.162169 0.017615 508 | 699 3.161134 0.017517 509 | 700 3.160106 0.017421 510 | 701 3.159082 0.017326 511 | 702 3.158064 0.017232 512 | 703 3.157051 0.017139 513 | 704 3.156043 0.017047 514 | 705 3.15504 0.016956 515 | 706 3.154043 0.016866 516 | 707 3.15305 0.016777 517 | 708 3.152063 0.016689 518 | 709 3.151081 0.016602 519 | 710 3.150104 0.016516 520 | 711 3.149131 0.016431 521 | 712 3.148164 0.016347 522 | 713 3.147201 0.016264 523 | 714 3.146244 0.016182 524 | 715 3.145291 0.0161 525 | 716 3.144342 0.01602 526 | 717 3.143399 0.01594 527 | 718 3.14246 0.015862 528 | 719 3.141526 0.015784 529 | 720 3.140597 0.015707 530 | 721 3.139672 0.015631 531 | 722 3.138752 0.015556 532 | 723 3.137836 0.015481 533 | 724 3.136925 0.015407 534 | 725 3.136018 0.015335 535 | 726 3.135116 0.015263 536 | 727 3.134218 0.015192 537 | 728 3.133324 0.015121 538 | 729 3.132435 0.015051 539 | 730 3.13155 0.014983 540 | 731 3.130669 0.014915 541 | 732 3.129792 0.014847 542 | 733 3.12892 0.014781 543 | 734 3.128052 0.014715 544 | 735 3.127188 0.01465 545 | 736 3.126328 0.014585 546 | 737 3.125472 0.014522 547 | 738 3.12462 0.014459 548 | 739 3.123772 0.014397 549 | 740 3.122929 0.014335 550 | 741 3.122089 0.014274 551 | 742 3.121253 0.014214 552 | 743 3.120421 0.014155 553 | 744 3.119593 0.014096 554 | 745 3.118769 0.014038 555 | 746 3.117948 0.01398 556 | 747 3.117132 0.013923 557 | 748 3.116319 0.013867 558 | 749 3.11551 0.013812 559 | 750 3.114705 0.013757 560 | 751 3.113903 0.013702 561 | 752 3.113105 0.013649 562 | 753 3.112311 0.013596 563 | 754 3.11152 0.013543 564 | 755 3.110733 0.013491 565 | 756 3.10995 0.01344 566 | 757 3.10917 0.013389 567 | 758 3.108393 0.013339 568 | 759 3.10762 0.01329 569 | 760 3.106851 0.013241 570 | 761 3.106085 0.013193 571 | 762 3.105323 0.013145 572 | 763 3.104564 0.013098 573 | 764 3.103808 0.013051 574 | 765 3.103056 0.013005 575 | 766 3.102307 0.012959 576 | 767 3.101562 0.012914 577 | 768 3.10082 0.012869 578 | 769 3.100081 0.012825 579 | 770 3.099345 0.012781 580 | 771 3.098613 0.012738 581 | 772 3.097884 0.012695 582 | 773 3.097157 0.012653 583 | 774 3.096435 0.012611 584 | 775 3.095715 0.01257 585 | 776 3.094999 0.012529 586 | 777 3.094285 0.012488 587 | 778 3.093575 0.012448 588 | 779 3.092868 0.012409 589 | 780 3.092163 0.012369 590 | 781 3.091462 0.012331 591 | 782 3.090764 0.012292 592 | 783 3.090069 0.012255 593 | 784 3.089376 0.012217 594 | 785 3.088687 0.01218 595 | 786 3.088001 0.012144 596 | 787 3.087317 0.012107 597 | 788 3.086636 0.012072 598 | 789 3.085958 0.012036 599 | 790 3.085284 0.012001 600 | 791 3.084611 0.011967 601 | 792 3.083942 0.011932 602 | 793 3.083276 0.011899 603 | 794 3.082612 0.011865 604 | 795 3.081951 0.011832 605 | 796 3.081292 0.0118 606 | 797 3.080637 0.011767 607 | 798 3.079984 0.011735 608 | 799 3.079334 0.011704 609 | 800 3.078686 0.011673 610 | 801 3.078041 0.011642 611 | 802 3.077399 0.011611 612 | 803 3.076759 0.011581 613 | 804 3.076122 0.011552 614 | 805 3.075488 0.011522 615 | 806 3.074856 0.011493 616 | 807 3.074226 0.011465 617 | 808 3.0736 0.011436 618 | 809 3.072975 0.011408 619 | 810 3.072353 0.011381 620 | 811 3.071734 0.011353 621 | 812 3.071117 0.011326 622 | 813 3.070503 0.0113 623 | 814 3.069891 0.011274 624 | 815 3.069281 0.011248 625 | 816 3.068674 0.011222 626 | 817 3.06807 0.011197 627 | 818 3.067467 0.011172 628 | 819 3.066867 0.011147 629 | 820 3.06627 0.011122 630 | 821 3.065675 0.011098 631 | 822 3.065082 0.011075 632 | 823 3.064491 0.011051 633 | 824 3.063903 0.011028 634 | 825 3.063317 0.011005 635 | 826 3.062733 0.010983 636 | 827 3.062152 0.01096 637 | 828 3.061573 0.010938 638 | 829 3.060996 0.010917 639 | 830 3.060421 0.010895 640 | 831 3.059848 0.010874 641 | 832 3.059278 0.010853 642 | 833 3.05871 0.010833 643 | 834 3.058144 0.010812 644 | 835 3.05758 0.010792 645 | 836 3.057019 0.010773 646 | 837 3.056459 0.010753 647 | 838 3.055902 0.010734 648 | 839 3.055347 0.010715 649 | 840 3.054794 0.010697 650 | 841 3.054243 0.010678 651 | 842 3.053694 0.01066 652 | 843 3.053147 0.010642 653 | 844 3.052603 0.010625 654 | 845 3.05206 0.010608 655 | 846 3.051519 0.010591 656 | 847 3.050981 0.010574 657 | 848 3.050444 0.010557 658 | 849 3.04991 0.010541 659 | 850 3.049377 0.010525 660 | 851 3.048847 0.010509 661 | 852 3.048318 0.010494 662 | 853 3.047792 0.010478 663 | 854 3.047267 0.010463 664 | 855 3.046745 0.010448 665 | 856 3.046224 0.010434 666 | 857 3.045706 0.010419 667 | 858 3.045189 0.010405 668 | 859 3.044674 0.010392 669 | 860 3.044162 0.010378 670 | 861 3.043651 0.010364 671 | 862 3.043142 0.010351 672 | 863 3.042636 0.010338 673 | 864 3.042131 0.010326 674 | 865 3.041628 0.010313 675 | 866 3.041128 0.010301 676 | 867 3.040629 0.010288 677 | 868 3.040132 0.010276 678 | 869 3.039637 0.010263 679 | 870 3.039144 0.010251 680 | 871 3.038653 0.010239 681 | 872 3.038164 0.010226 682 | 873 3.037676 0.010214 683 | 874 3.03719 0.010202 684 | 875 3.036706 0.01019 685 | 876 3.036224 0.010178 686 | 877 3.035743 0.010166 687 | 878 3.035264 0.010153 688 | 879 3.034787 0.010141 689 | 880 3.034312 0.010129 690 | 881 3.033838 0.010117 691 | 882 3.033365 0.010105 692 | 883 3.032895 0.010093 693 | 884 3.032426 0.010081 694 | 885 3.031959 0.01007 695 | 886 3.031493 0.010058 696 | 887 3.031029 0.010046 697 | 888 3.030566 0.010034 698 | 889 3.030105 0.010022 699 | 890 3.029646 0.01001 700 | 891 3.029188 0.009999 701 | 892 3.028732 0.009987 702 | 893 3.028277 0.009975 703 | 894 3.027823 0.009964 704 | 895 3.027372 0.009952 705 | 896 3.026921 0.009941 706 | 897 3.026473 0.009929 707 | 898 3.026025 0.009917 708 | 899 3.025579 0.009906 709 | 900 3.025135 0.009894 710 | 901 3.024692 0.009883 711 | 902 3.02425 0.009872 712 | 903 3.02381 0.00986 713 | 904 3.023371 0.009849 714 | 905 3.022934 0.009837 715 | 906 3.022498 0.009826 716 | 907 3.022063 0.009815 717 | 908 3.02163 0.009804 718 | 909 3.021198 0.009792 719 | 910 3.020768 0.009781 720 | 911 3.020339 0.00977 721 | 912 3.019911 0.009759 722 | 913 3.019485 0.009748 723 | 914 3.019059 0.009737 724 | 915 3.018636 0.009726 725 | 916 3.018213 0.009715 726 | 917 3.017792 0.009704 727 | 918 3.017372 0.009693 728 | 919 3.016953 0.009682 729 | 920 3.016536 0.009671 730 | 921 3.01612 0.00966 731 | 922 3.015705 0.009649 732 | 923 3.015291 0.009638 733 | 924 3.014879 0.009627 734 | 925 3.014468 0.009616 735 | 926 3.014058 0.009605 736 | 927 3.013649 0.009595 737 | 928 3.013242 0.009584 738 | 929 3.012836 0.009573 739 | 930 3.01243 0.009563 740 | 931 3.012027 0.009552 741 | 932 3.011624 0.009541 742 | 933 3.011222 0.009531 743 | 934 3.010822 0.00952 744 | 935 3.010423 0.00951 745 | 936 3.010025 0.009499 746 | 937 3.009628 0.009488 747 | 938 3.009232 0.009478 748 | 939 3.008837 0.009468 749 | 940 3.008444 0.009457 750 | 941 3.008052 0.009447 751 | 942 3.007661 0.009436 752 | 943 3.00727 0.009426 753 | 944 3.006881 0.009416 754 | 945 3.006494 0.009405 755 | 946 3.006107 0.009395 756 | 947 3.005721 0.009385 757 | 948 3.005336 0.009374 758 | 949 3.004953 0.009364 759 | 950 3.00457 0.009354 760 | 951 3.004189 0.009344 761 | 952 3.003808 0.009334 762 | 953 3.003429 0.009323 763 | 954 3.00305 0.009313 764 | 955 3.002673 0.009303 765 | 956 3.002297 0.009293 766 | 957 3.001922 0.009283 767 | 958 3.001547 0.009273 768 | 959 3.001174 0.009263 769 | 960 3.000802 0.009253 770 | 961 3.000431 0.009243 771 | 962 3.00006 0.009233 772 | 963 2.999691 0.009223 773 | 964 2.999323 0.009214 774 | 965 2.998955 0.009204 775 | 966 2.998589 0.009194 776 | 967 2.998224 0.009184 777 | 968 2.997859 0.009174 778 | 969 2.997496 0.009164 779 | 970 2.997133 0.009155 780 | 971 2.996772 0.009145 781 | 972 2.996411 0.009135 782 | 973 2.996051 0.009126 783 | 974 2.995692 0.009116 784 | 975 2.995335 0.009106 785 | 976 2.994978 0.009097 786 | 977 2.994622 0.009087 787 | 978 2.994267 0.009077 788 | 979 2.993912 0.009068 789 | 980 2.993559 0.009058 790 | 981 2.993207 0.009049 791 | 982 2.992855 0.009039 792 | 983 2.992505 0.00903 793 | 984 2.992155 0.00902 794 | 985 2.991806 0.009011 795 | 986 2.991458 0.009002 796 | 987 2.991111 0.008992 797 | 988 2.990764 0.008983 798 | 989 2.990419 0.008973 799 | 990 2.990074 0.008964 800 | 991 2.98973 0.008955 801 | 992 2.989388 0.008945 802 | 993 2.989045 0.008936 803 | 994 2.988704 0.008927 804 | 995 2.988364 0.008918 805 | 996 2.988024 0.008909 806 | 997 2.987685 0.008899 807 | 998 2.987347 0.00889 808 | 999 2.98701 0.008881 -------------------------------------------------------------------------------- /example/Example5.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "'''\n", 10 | "TORCWA Example5\n", 11 | "Shape derivative - Maximize anisotropy\n", 12 | "\n", 13 | "'''\n", 14 | "# Import\n", 15 | "import numpy as np\n", 16 | "import torch\n", 17 | "import scipy.io\n", 18 | "from matplotlib import pyplot as plt\n", 19 | "import time\n", 20 | "\n", 21 | "import torcwa\n", 22 | "import Materials\n", 23 | "\n", 24 | "# Hardware\n", 25 | "# If GPU support TF32 tensor core, the matmul operation is faster than FP32 but with less precision.\n", 26 | "# If you need accurate operation, you have to disable the flag below.\n", 27 | "torch.backends.cuda.matmul.allow_tf32 = False\n", 28 | "sim_dtype = torch.complex64\n", 29 | "geo_dtype = torch.float32\n", 30 | "device = torch.device('cuda')\n", 31 | "\n", 32 | "# Simulation environment\n", 33 | "# light\n", 34 | "lamb0 = torch.tensor(532.,dtype=geo_dtype,device=device) # nm\n", 35 | "inc_ang = 0.*(np.pi/180) # radian\n", 36 | "azi_ang = 0.*(np.pi/180) # radian\n", 37 | "\n", 38 | "# material\n", 39 | "substrate_eps = 1.46**2\n", 40 | "silicon_eps = Materials.aSiH.apply(lamb0)**2\n", 41 | "\n", 42 | "# geometry\n", 43 | "L = [300., 300.] # nm / nm\n", 44 | "torcwa.rcwa_geo.dtype = geo_dtype\n", 45 | "torcwa.rcwa_geo.device = device\n", 46 | "torcwa.rcwa_geo.Lx = L[0]\n", 47 | "torcwa.rcwa_geo.Ly = L[1]\n", 48 | "torcwa.rcwa_geo.nx = 300\n", 49 | "torcwa.rcwa_geo.ny = 300\n", 50 | "torcwa.rcwa_geo.grid()\n", 51 | "torcwa.rcwa_geo.edge_sharpness = 500.\n", 52 | "\n", 53 | "x_axis = torcwa.rcwa_geo.x.cpu()\n", 54 | "y_axis = torcwa.rcwa_geo.y.cpu()\n", 55 | "\n", 56 | "# layers\n", 57 | "# layer0_geometry = torcwa.rcwa_geo.rectangle(Wx=180.,Wy=100.,Cx=L[0]/2.,Cy=L[1]/2.)\n", 58 | "# layer0_eps = layer0_geometry*silicon_eps + (1.-layer0_geometry)\n", 59 | "layer0_thickness = 250." 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 2, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "# Objective function\n", 69 | "\n", 70 | "def objective_function(W):\n", 71 | " order_N = 10\n", 72 | " order = [order_N,order_N]\n", 73 | "\n", 74 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device)\n", 75 | " sim.add_input_layer(eps=substrate_eps)\n", 76 | " sim.set_incident_angle(inc_ang=inc_ang,azi_ang=azi_ang)\n", 77 | " layer0_geometry = torcwa.rcwa_geo.rectangle(Wx=W[0],Wy=W[1],Cx=L[0]/2.,Cy=L[1]/2.)\n", 78 | " layer0_eps = layer0_geometry*silicon_eps + (1.-layer0_geometry)\n", 79 | " sim.add_layer(thickness=layer0_thickness,eps=layer0_eps)\n", 80 | " sim.solve_global_smatrix()\n", 81 | " txx = sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='xx',ref_order=[0,0])\n", 82 | " tyy = sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='yy',ref_order=[0,0])\n", 83 | "\n", 84 | " delta = torch.abs(tyy-txx)\n", 85 | " return delta" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 3, 91 | "metadata": {}, 92 | "outputs": [ 93 | { 94 | "name": "stdout", 95 | "output_type": "stream", 96 | "text": [ 97 | "Iteration: 0 / Delta: 0.287 / Elapsed time: 4 s\n", 98 | "Iteration: 1 / Delta: 0.3 / Elapsed time: 5 s\n", 99 | "Iteration: 2 / Delta: 0.311 / Elapsed time: 6 s\n", 100 | "Iteration: 3 / Delta: 0.313 / Elapsed time: 7 s\n", 101 | "Iteration: 4 / Delta: 0.326 / Elapsed time: 8 s\n", 102 | "Iteration: 5 / Delta: 0.345 / Elapsed time: 9 s\n", 103 | "Iteration: 6 / Delta: 0.351 / Elapsed time: 10 s\n", 104 | "Iteration: 7 / Delta: 0.37 / Elapsed time: 11 s\n", 105 | "Iteration: 8 / Delta: 0.377 / Elapsed time: 13 s\n", 106 | "Iteration: 9 / Delta: 0.398 / Elapsed time: 14 s\n", 107 | "Iteration: 10 / Delta: 0.421 / Elapsed time: 15 s\n", 108 | "Iteration: 11 / Delta: 0.424 / Elapsed time: 16 s\n", 109 | "Iteration: 12 / Delta: 0.458 / Elapsed time: 17 s\n", 110 | "Iteration: 13 / Delta: 0.477 / Elapsed time: 18 s\n", 111 | "Iteration: 14 / Delta: 0.485 / Elapsed time: 19 s\n", 112 | "Iteration: 15 / Delta: 0.52 / Elapsed time: 20 s\n", 113 | "Iteration: 16 / Delta: 0.542 / Elapsed time: 21 s\n", 114 | "Iteration: 17 / Delta: 0.566 / Elapsed time: 22 s\n", 115 | "Iteration: 18 / Delta: 0.588 / Elapsed time: 24 s\n", 116 | "Iteration: 19 / Delta: 0.623 / Elapsed time: 25 s\n", 117 | "Iteration: 20 / Delta: 0.657 / Elapsed time: 26 s\n", 118 | "Iteration: 21 / Delta: 0.667 / Elapsed time: 27 s\n", 119 | "Iteration: 22 / Delta: 0.731 / Elapsed time: 28 s\n", 120 | "Iteration: 23 / Delta: 0.745 / Elapsed time: 29 s\n", 121 | "Iteration: 24 / Delta: 0.771 / Elapsed time: 30 s\n", 122 | "Iteration: 25 / Delta: 0.823 / Elapsed time: 31 s\n", 123 | "Iteration: 26 / Delta: 0.841 / Elapsed time: 32 s\n", 124 | "Iteration: 27 / Delta: 0.874 / Elapsed time: 33 s\n", 125 | "Iteration: 28 / Delta: 0.902 / Elapsed time: 35 s\n", 126 | "Iteration: 29 / Delta: 0.933 / Elapsed time: 36 s\n", 127 | "Iteration: 30 / Delta: 0.941 / Elapsed time: 37 s\n", 128 | "Iteration: 31 / Delta: 0.965 / Elapsed time: 38 s\n", 129 | "Iteration: 32 / Delta: 0.979 / Elapsed time: 39 s\n", 130 | "Iteration: 33 / Delta: 0.982 / Elapsed time: 40 s\n", 131 | "Iteration: 34 / Delta: 0.992 / Elapsed time: 41 s\n", 132 | "Iteration: 35 / Delta: 0.994 / Elapsed time: 42 s\n", 133 | "Iteration: 36 / Delta: 0.996 / Elapsed time: 43 s\n", 134 | "Iteration: 37 / Delta: 0.999 / Elapsed time: 44 s\n", 135 | "Iteration: 38 / Delta: 1.0 / Elapsed time: 46 s\n", 136 | "Iteration: 39 / Delta: 0.999 / Elapsed time: 47 s\n", 137 | "Iteration: 40 / Delta: 0.999 / Elapsed time: 48 s\n", 138 | "Iteration: 41 / Delta: 0.999 / Elapsed time: 49 s\n", 139 | "Iteration: 42 / Delta: 0.999 / Elapsed time: 50 s\n", 140 | "Iteration: 43 / Delta: 0.999 / Elapsed time: 51 s\n", 141 | "Iteration: 44 / Delta: 1.0 / Elapsed time: 52 s\n", 142 | "Iteration: 45 / Delta: 1.0 / Elapsed time: 53 s\n", 143 | "Iteration: 46 / Delta: 1.0 / Elapsed time: 54 s\n", 144 | "Iteration: 47 / Delta: 1.0 / Elapsed time: 55 s\n", 145 | "Iteration: 48 / Delta: 1.0 / Elapsed time: 56 s\n", 146 | "Iteration: 49 / Delta: 1.001 / Elapsed time: 58 s\n", 147 | "Iteration: 50 / Delta: 1.0 / Elapsed time: 59 s\n", 148 | "Iteration: 51 / Delta: 1.0 / Elapsed time: 60 s\n", 149 | "Iteration: 52 / Delta: 1.0 / Elapsed time: 61 s\n", 150 | "Iteration: 53 / Delta: 1.001 / Elapsed time: 62 s\n", 151 | "Iteration: 54 / Delta: 1.001 / Elapsed time: 63 s\n", 152 | "Iteration: 55 / Delta: 1.001 / Elapsed time: 64 s\n", 153 | "Iteration: 56 / Delta: 1.002 / Elapsed time: 65 s\n", 154 | "Iteration: 57 / Delta: 1.003 / Elapsed time: 66 s\n", 155 | "Iteration: 58 / Delta: 1.003 / Elapsed time: 67 s\n", 156 | "Iteration: 59 / Delta: 1.004 / Elapsed time: 69 s\n", 157 | "Iteration: 60 / Delta: 1.004 / Elapsed time: 70 s\n", 158 | "Iteration: 61 / Delta: 1.005 / Elapsed time: 71 s\n", 159 | "Iteration: 62 / Delta: 1.006 / Elapsed time: 72 s\n", 160 | "Iteration: 63 / Delta: 1.006 / Elapsed time: 73 s\n", 161 | "Iteration: 64 / Delta: 1.006 / Elapsed time: 74 s\n", 162 | "Iteration: 65 / Delta: 1.006 / Elapsed time: 75 s\n", 163 | "Iteration: 66 / Delta: 1.006 / Elapsed time: 76 s\n", 164 | "Iteration: 67 / Delta: 1.006 / Elapsed time: 77 s\n", 165 | "Iteration: 68 / Delta: 1.006 / Elapsed time: 79 s\n", 166 | "Iteration: 69 / Delta: 1.006 / Elapsed time: 80 s\n", 167 | "Iteration: 70 / Delta: 1.007 / Elapsed time: 81 s\n", 168 | "Iteration: 71 / Delta: 1.007 / Elapsed time: 82 s\n", 169 | "Iteration: 72 / Delta: 1.007 / Elapsed time: 83 s\n", 170 | "Iteration: 73 / Delta: 1.008 / Elapsed time: 84 s\n", 171 | "Iteration: 74 / Delta: 1.01 / Elapsed time: 85 s\n", 172 | "Iteration: 75 / Delta: 1.012 / Elapsed time: 86 s\n", 173 | "Iteration: 76 / Delta: 1.015 / Elapsed time: 87 s\n", 174 | "Iteration: 77 / Delta: 1.017 / Elapsed time: 89 s\n", 175 | "Iteration: 78 / Delta: 1.017 / Elapsed time: 90 s\n", 176 | "Iteration: 79 / Delta: 1.018 / Elapsed time: 91 s\n", 177 | "Iteration: 80 / Delta: 1.02 / Elapsed time: 92 s\n", 178 | "Iteration: 81 / Delta: 1.021 / Elapsed time: 93 s\n", 179 | "Iteration: 82 / Delta: 1.024 / Elapsed time: 94 s\n", 180 | "Iteration: 83 / Delta: 1.029 / Elapsed time: 95 s\n", 181 | "Iteration: 84 / Delta: 1.033 / Elapsed time: 96 s\n", 182 | "Iteration: 85 / Delta: 1.033 / Elapsed time: 97 s\n", 183 | "Iteration: 86 / Delta: 1.034 / Elapsed time: 98 s\n", 184 | "Iteration: 87 / Delta: 1.035 / Elapsed time: 99 s\n", 185 | "Iteration: 88 / Delta: 1.04 / Elapsed time: 101 s\n", 186 | "Iteration: 89 / Delta: 1.048 / Elapsed time: 102 s\n", 187 | "Iteration: 90 / Delta: 1.05 / Elapsed time: 103 s\n", 188 | "Iteration: 91 / Delta: 1.052 / Elapsed time: 104 s\n", 189 | "Iteration: 92 / Delta: 1.055 / Elapsed time: 105 s\n", 190 | "Iteration: 93 / Delta: 1.061 / Elapsed time: 106 s\n", 191 | "Iteration: 94 / Delta: 1.068 / Elapsed time: 107 s\n", 192 | "Iteration: 95 / Delta: 1.069 / Elapsed time: 108 s\n", 193 | "Iteration: 96 / Delta: 1.07 / Elapsed time: 109 s\n", 194 | "Iteration: 97 / Delta: 1.072 / Elapsed time: 111 s\n", 195 | "Iteration: 98 / Delta: 1.08 / Elapsed time: 112 s\n", 196 | "Iteration: 99 / Delta: 1.084 / Elapsed time: 113 s\n", 197 | "Iteration: 100 / Delta: 1.085 / Elapsed time: 114 s\n", 198 | "Iteration: 101 / Delta: 1.087 / Elapsed time: 115 s\n", 199 | "Iteration: 102 / Delta: 1.091 / Elapsed time: 116 s\n", 200 | "Iteration: 103 / Delta: 1.096 / Elapsed time: 117 s\n", 201 | "Iteration: 104 / Delta: 1.097 / Elapsed time: 118 s\n", 202 | "Iteration: 105 / Delta: 1.097 / Elapsed time: 119 s\n", 203 | "Iteration: 106 / Delta: 1.098 / Elapsed time: 120 s\n", 204 | "Iteration: 107 / Delta: 1.1 / Elapsed time: 122 s\n", 205 | "Iteration: 108 / Delta: 1.102 / Elapsed time: 123 s\n", 206 | "Iteration: 109 / Delta: 1.102 / Elapsed time: 124 s\n", 207 | "Iteration: 110 / Delta: 1.103 / Elapsed time: 125 s\n", 208 | "Iteration: 111 / Delta: 1.104 / Elapsed time: 126 s\n", 209 | "Iteration: 112 / Delta: 1.104 / Elapsed time: 127 s\n", 210 | "Iteration: 113 / Delta: 1.105 / Elapsed time: 128 s\n", 211 | "Iteration: 114 / Delta: 1.105 / Elapsed time: 129 s\n", 212 | "Iteration: 115 / Delta: 1.104 / Elapsed time: 130 s\n", 213 | "Iteration: 116 / Delta: 1.104 / Elapsed time: 132 s\n", 214 | "Iteration: 117 / Delta: 1.104 / Elapsed time: 133 s\n", 215 | "Iteration: 118 / Delta: 1.104 / Elapsed time: 134 s\n", 216 | "Iteration: 119 / Delta: 1.105 / Elapsed time: 135 s\n", 217 | "Iteration: 120 / Delta: 1.105 / Elapsed time: 136 s\n", 218 | "Iteration: 121 / Delta: 1.106 / Elapsed time: 137 s\n", 219 | "Iteration: 122 / Delta: 1.106 / Elapsed time: 138 s\n", 220 | "Iteration: 123 / Delta: 1.107 / Elapsed time: 139 s\n", 221 | "Iteration: 124 / Delta: 1.107 / Elapsed time: 140 s\n", 222 | "Iteration: 125 / Delta: 1.107 / Elapsed time: 142 s\n", 223 | "Iteration: 126 / Delta: 1.107 / Elapsed time: 143 s\n", 224 | "Iteration: 127 / Delta: 1.107 / Elapsed time: 144 s\n", 225 | "Iteration: 128 / Delta: 1.107 / Elapsed time: 145 s\n", 226 | "Iteration: 129 / Delta: 1.107 / Elapsed time: 146 s\n", 227 | "Iteration: 130 / Delta: 1.107 / Elapsed time: 147 s\n", 228 | "Iteration: 131 / Delta: 1.107 / Elapsed time: 148 s\n", 229 | "Iteration: 132 / Delta: 1.107 / Elapsed time: 149 s\n", 230 | "Iteration: 133 / Delta: 1.108 / Elapsed time: 150 s\n", 231 | "Iteration: 134 / Delta: 1.107 / Elapsed time: 151 s\n", 232 | "Iteration: 135 / Delta: 1.107 / Elapsed time: 153 s\n", 233 | "Iteration: 136 / Delta: 1.107 / Elapsed time: 154 s\n", 234 | "Iteration: 137 / Delta: 1.107 / Elapsed time: 155 s\n", 235 | "Iteration: 138 / Delta: 1.108 / Elapsed time: 156 s\n", 236 | "Iteration: 139 / Delta: 1.107 / Elapsed time: 157 s\n", 237 | "Iteration: 140 / Delta: 1.107 / Elapsed time: 158 s\n", 238 | "Iteration: 141 / Delta: 1.108 / Elapsed time: 159 s\n", 239 | "Iteration: 142 / Delta: 1.107 / Elapsed time: 160 s\n", 240 | "Iteration: 143 / Delta: 1.107 / Elapsed time: 161 s\n", 241 | "Iteration: 144 / Delta: 1.107 / Elapsed time: 162 s\n", 242 | "Iteration: 145 / Delta: 1.108 / Elapsed time: 164 s\n", 243 | "Iteration: 146 / Delta: 1.108 / Elapsed time: 165 s\n", 244 | "Iteration: 147 / Delta: 1.108 / Elapsed time: 166 s\n", 245 | "Iteration: 148 / Delta: 1.107 / Elapsed time: 167 s\n", 246 | "Iteration: 149 / Delta: 1.108 / Elapsed time: 168 s\n", 247 | "Iteration: 150 / Delta: 1.107 / Elapsed time: 169 s\n", 248 | "Iteration: 151 / Delta: 1.108 / Elapsed time: 170 s\n", 249 | "Iteration: 152 / Delta: 1.108 / Elapsed time: 171 s\n", 250 | "Iteration: 153 / Delta: 1.108 / Elapsed time: 172 s\n", 251 | "Iteration: 154 / Delta: 1.108 / Elapsed time: 174 s\n", 252 | "Iteration: 155 / Delta: 1.108 / Elapsed time: 175 s\n", 253 | "Iteration: 156 / Delta: 1.108 / Elapsed time: 176 s\n", 254 | "Iteration: 157 / Delta: 1.108 / Elapsed time: 177 s\n", 255 | "Iteration: 158 / Delta: 1.107 / Elapsed time: 178 s\n", 256 | "Iteration: 159 / Delta: 1.107 / Elapsed time: 179 s\n", 257 | "Iteration: 160 / Delta: 1.107 / Elapsed time: 180 s\n", 258 | "Iteration: 161 / Delta: 1.108 / Elapsed time: 181 s\n", 259 | "Iteration: 162 / Delta: 1.107 / Elapsed time: 182 s\n", 260 | "Iteration: 163 / Delta: 1.107 / Elapsed time: 184 s\n", 261 | "Iteration: 164 / Delta: 1.107 / Elapsed time: 185 s\n", 262 | "Iteration: 165 / Delta: 1.108 / Elapsed time: 186 s\n", 263 | "Iteration: 166 / Delta: 1.107 / Elapsed time: 187 s\n", 264 | "Iteration: 167 / Delta: 1.108 / Elapsed time: 188 s\n", 265 | "Iteration: 168 / Delta: 1.108 / Elapsed time: 189 s\n", 266 | "Iteration: 169 / Delta: 1.107 / Elapsed time: 190 s\n", 267 | "Iteration: 170 / Delta: 1.107 / Elapsed time: 191 s\n", 268 | "Iteration: 171 / Delta: 1.108 / Elapsed time: 192 s\n", 269 | "Iteration: 172 / Delta: 1.108 / Elapsed time: 193 s\n", 270 | "Iteration: 173 / Delta: 1.107 / Elapsed time: 195 s\n", 271 | "Iteration: 174 / Delta: 1.107 / Elapsed time: 196 s\n", 272 | "Iteration: 175 / Delta: 1.108 / Elapsed time: 197 s\n", 273 | "Iteration: 176 / Delta: 1.107 / Elapsed time: 198 s\n", 274 | "Iteration: 177 / Delta: 1.107 / Elapsed time: 199 s\n", 275 | "Iteration: 178 / Delta: 1.108 / Elapsed time: 200 s\n", 276 | "Iteration: 179 / Delta: 1.107 / Elapsed time: 201 s\n", 277 | "Iteration: 180 / Delta: 1.107 / Elapsed time: 202 s\n", 278 | "Iteration: 181 / Delta: 1.108 / Elapsed time: 203 s\n", 279 | "Iteration: 182 / Delta: 1.108 / Elapsed time: 204 s\n", 280 | "Iteration: 183 / Delta: 1.107 / Elapsed time: 206 s\n", 281 | "Iteration: 184 / Delta: 1.107 / Elapsed time: 207 s\n", 282 | "Iteration: 185 / Delta: 1.107 / Elapsed time: 208 s\n", 283 | "Iteration: 186 / Delta: 1.108 / Elapsed time: 209 s\n", 284 | "Iteration: 187 / Delta: 1.108 / Elapsed time: 210 s\n", 285 | "Iteration: 188 / Delta: 1.107 / Elapsed time: 211 s\n", 286 | "Iteration: 189 / Delta: 1.107 / Elapsed time: 212 s\n", 287 | "Iteration: 190 / Delta: 1.108 / Elapsed time: 213 s\n", 288 | "Iteration: 191 / Delta: 1.107 / Elapsed time: 214 s\n", 289 | "Iteration: 192 / Delta: 1.108 / Elapsed time: 216 s\n", 290 | "Iteration: 193 / Delta: 1.108 / Elapsed time: 217 s\n", 291 | "Iteration: 194 / Delta: 1.107 / Elapsed time: 218 s\n", 292 | "Iteration: 195 / Delta: 1.107 / Elapsed time: 219 s\n", 293 | "Iteration: 196 / Delta: 1.107 / Elapsed time: 220 s\n", 294 | "Iteration: 197 / Delta: 1.107 / Elapsed time: 221 s\n", 295 | "Iteration: 198 / Delta: 1.108 / Elapsed time: 222 s\n", 296 | "Iteration: 199 / Delta: 1.107 / Elapsed time: 223 s\n", 297 | "Iteration: 200 / Delta: 1.107 / Elapsed time: 224 s\n", 298 | "Iteration: 201 / Delta: 1.107 / Elapsed time: 226 s\n", 299 | "Iteration: 202 / Delta: 1.107 / Elapsed time: 227 s\n", 300 | "Iteration: 203 / Delta: 1.108 / Elapsed time: 228 s\n", 301 | "Iteration: 204 / Delta: 1.108 / Elapsed time: 229 s\n", 302 | "Iteration: 205 / Delta: 1.108 / Elapsed time: 230 s\n", 303 | "Iteration: 206 / Delta: 1.107 / Elapsed time: 231 s\n", 304 | "Iteration: 207 / Delta: 1.107 / Elapsed time: 232 s\n", 305 | "Iteration: 208 / Delta: 1.108 / Elapsed time: 233 s\n", 306 | "Iteration: 209 / Delta: 1.107 / Elapsed time: 234 s\n", 307 | "Iteration: 210 / Delta: 1.108 / Elapsed time: 235 s\n", 308 | "Iteration: 211 / Delta: 1.107 / Elapsed time: 237 s\n", 309 | "Iteration: 212 / Delta: 1.108 / Elapsed time: 238 s\n", 310 | "Iteration: 213 / Delta: 1.107 / Elapsed time: 239 s\n", 311 | "Iteration: 214 / Delta: 1.108 / Elapsed time: 240 s\n", 312 | "Iteration: 215 / Delta: 1.107 / Elapsed time: 241 s\n", 313 | "Iteration: 216 / Delta: 1.107 / Elapsed time: 242 s\n", 314 | "Iteration: 217 / Delta: 1.107 / Elapsed time: 243 s\n", 315 | "Iteration: 218 / Delta: 1.107 / Elapsed time: 244 s\n", 316 | "Iteration: 219 / Delta: 1.108 / Elapsed time: 245 s\n", 317 | "Iteration: 220 / Delta: 1.107 / Elapsed time: 247 s\n", 318 | "Iteration: 221 / Delta: 1.107 / Elapsed time: 248 s\n", 319 | "Iteration: 222 / Delta: 1.107 / Elapsed time: 249 s\n", 320 | "Iteration: 223 / Delta: 1.107 / Elapsed time: 250 s\n", 321 | "Iteration: 224 / Delta: 1.107 / Elapsed time: 251 s\n", 322 | "Iteration: 225 / Delta: 1.107 / Elapsed time: 252 s\n", 323 | "Iteration: 226 / Delta: 1.108 / Elapsed time: 253 s\n", 324 | "Iteration: 227 / Delta: 1.108 / Elapsed time: 254 s\n", 325 | "Iteration: 228 / Delta: 1.108 / Elapsed time: 255 s\n", 326 | "Iteration: 229 / Delta: 1.107 / Elapsed time: 256 s\n", 327 | "Iteration: 230 / Delta: 1.108 / Elapsed time: 258 s\n", 328 | "Iteration: 231 / Delta: 1.108 / Elapsed time: 259 s\n", 329 | "Iteration: 232 / Delta: 1.108 / Elapsed time: 260 s\n", 330 | "Iteration: 233 / Delta: 1.107 / Elapsed time: 261 s\n", 331 | "Iteration: 234 / Delta: 1.108 / Elapsed time: 262 s\n", 332 | "Iteration: 235 / Delta: 1.107 / Elapsed time: 263 s\n", 333 | "Iteration: 236 / Delta: 1.107 / Elapsed time: 264 s\n", 334 | "Iteration: 237 / Delta: 1.108 / Elapsed time: 265 s\n", 335 | "Iteration: 238 / Delta: 1.108 / Elapsed time: 266 s\n", 336 | "Iteration: 239 / Delta: 1.107 / Elapsed time: 267 s\n", 337 | "Iteration: 240 / Delta: 1.107 / Elapsed time: 269 s\n", 338 | "Iteration: 241 / Delta: 1.108 / Elapsed time: 270 s\n", 339 | "Iteration: 242 / Delta: 1.108 / Elapsed time: 271 s\n", 340 | "Iteration: 243 / Delta: 1.107 / Elapsed time: 272 s\n", 341 | "Iteration: 244 / Delta: 1.108 / Elapsed time: 273 s\n", 342 | "Iteration: 245 / Delta: 1.107 / Elapsed time: 274 s\n", 343 | "Iteration: 246 / Delta: 1.107 / Elapsed time: 275 s\n", 344 | "Iteration: 247 / Delta: 1.107 / Elapsed time: 276 s\n", 345 | "Iteration: 248 / Delta: 1.107 / Elapsed time: 277 s\n", 346 | "Iteration: 249 / Delta: 1.107 / Elapsed time: 278 s\n", 347 | "Iteration: 250 / Delta: 1.107 / Elapsed time: 280 s\n", 348 | "Iteration: 251 / Delta: 1.107 / Elapsed time: 281 s\n", 349 | "Iteration: 252 / Delta: 1.107 / Elapsed time: 282 s\n", 350 | "Iteration: 253 / Delta: 1.108 / Elapsed time: 283 s\n", 351 | "Iteration: 254 / Delta: 1.108 / Elapsed time: 284 s\n", 352 | "Iteration: 255 / Delta: 1.107 / Elapsed time: 285 s\n", 353 | "Iteration: 256 / Delta: 1.107 / Elapsed time: 286 s\n", 354 | "Iteration: 257 / Delta: 1.107 / Elapsed time: 287 s\n", 355 | "Iteration: 258 / Delta: 1.107 / Elapsed time: 288 s\n", 356 | "Iteration: 259 / Delta: 1.107 / Elapsed time: 289 s\n", 357 | "Iteration: 260 / Delta: 1.108 / Elapsed time: 291 s\n", 358 | "Iteration: 261 / Delta: 1.107 / Elapsed time: 292 s\n", 359 | "Iteration: 262 / Delta: 1.107 / Elapsed time: 293 s\n", 360 | "Iteration: 263 / Delta: 1.108 / Elapsed time: 294 s\n", 361 | "Iteration: 264 / Delta: 1.107 / Elapsed time: 295 s\n", 362 | "Iteration: 265 / Delta: 1.108 / Elapsed time: 296 s\n", 363 | "Iteration: 266 / Delta: 1.107 / Elapsed time: 297 s\n", 364 | "Iteration: 267 / Delta: 1.107 / Elapsed time: 298 s\n", 365 | "Iteration: 268 / Delta: 1.108 / Elapsed time: 299 s\n", 366 | "Iteration: 269 / Delta: 1.108 / Elapsed time: 300 s\n", 367 | "Iteration: 270 / Delta: 1.108 / Elapsed time: 302 s\n", 368 | "Iteration: 271 / Delta: 1.108 / Elapsed time: 303 s\n", 369 | "Iteration: 272 / Delta: 1.107 / Elapsed time: 304 s\n", 370 | "Iteration: 273 / Delta: 1.108 / Elapsed time: 305 s\n", 371 | "Iteration: 274 / Delta: 1.107 / Elapsed time: 306 s\n", 372 | "Iteration: 275 / Delta: 1.107 / Elapsed time: 307 s\n", 373 | "Iteration: 276 / Delta: 1.107 / Elapsed time: 308 s\n", 374 | "Iteration: 277 / Delta: 1.108 / Elapsed time: 309 s\n", 375 | "Iteration: 278 / Delta: 1.107 / Elapsed time: 310 s\n", 376 | "Iteration: 279 / Delta: 1.108 / Elapsed time: 311 s\n", 377 | "Iteration: 280 / Delta: 1.107 / Elapsed time: 312 s\n", 378 | "Iteration: 281 / Delta: 1.108 / Elapsed time: 314 s\n", 379 | "Iteration: 282 / Delta: 1.108 / Elapsed time: 315 s\n", 380 | "Iteration: 283 / Delta: 1.107 / Elapsed time: 316 s\n", 381 | "Iteration: 284 / Delta: 1.108 / Elapsed time: 317 s\n", 382 | "Iteration: 285 / Delta: 1.107 / Elapsed time: 318 s\n", 383 | "Iteration: 286 / Delta: 1.108 / Elapsed time: 319 s\n", 384 | "Iteration: 287 / Delta: 1.108 / Elapsed time: 320 s\n", 385 | "Iteration: 288 / Delta: 1.108 / Elapsed time: 321 s\n", 386 | "Iteration: 289 / Delta: 1.107 / Elapsed time: 322 s\n", 387 | "Iteration: 290 / Delta: 1.108 / Elapsed time: 323 s\n", 388 | "Iteration: 291 / Delta: 1.108 / Elapsed time: 325 s\n", 389 | "Iteration: 292 / Delta: 1.107 / Elapsed time: 326 s\n", 390 | "Iteration: 293 / Delta: 1.107 / Elapsed time: 327 s\n", 391 | "Iteration: 294 / Delta: 1.107 / Elapsed time: 328 s\n", 392 | "Iteration: 295 / Delta: 1.107 / Elapsed time: 329 s\n", 393 | "Iteration: 296 / Delta: 1.107 / Elapsed time: 330 s\n", 394 | "Iteration: 297 / Delta: 1.107 / Elapsed time: 331 s\n", 395 | "Iteration: 298 / Delta: 1.107 / Elapsed time: 332 s\n", 396 | "Iteration: 299 / Delta: 1.108 / Elapsed time: 334 s\n", 397 | "Iteration: 300 / Delta: 1.107 / Elapsed time: 335 s\n", 398 | "Iteration: 301 / Delta: 1.107 / Elapsed time: 336 s\n", 399 | "Iteration: 302 / Delta: 1.108 / Elapsed time: 337 s\n", 400 | "Iteration: 303 / Delta: 1.108 / Elapsed time: 338 s\n", 401 | "Iteration: 304 / Delta: 1.107 / Elapsed time: 339 s\n", 402 | "Iteration: 305 / Delta: 1.108 / Elapsed time: 340 s\n", 403 | "Iteration: 306 / Delta: 1.107 / Elapsed time: 341 s\n", 404 | "Iteration: 307 / Delta: 1.108 / Elapsed time: 342 s\n", 405 | "Iteration: 308 / Delta: 1.107 / Elapsed time: 344 s\n", 406 | "Iteration: 309 / Delta: 1.107 / Elapsed time: 345 s\n", 407 | "Iteration: 310 / Delta: 1.108 / Elapsed time: 346 s\n", 408 | "Iteration: 311 / Delta: 1.108 / Elapsed time: 347 s\n", 409 | "Iteration: 312 / Delta: 1.108 / Elapsed time: 348 s\n", 410 | "Iteration: 313 / Delta: 1.108 / Elapsed time: 349 s\n", 411 | "Iteration: 314 / Delta: 1.108 / Elapsed time: 350 s\n", 412 | "Iteration: 315 / Delta: 1.108 / Elapsed time: 351 s\n", 413 | "Iteration: 316 / Delta: 1.107 / Elapsed time: 352 s\n", 414 | "Iteration: 317 / Delta: 1.107 / Elapsed time: 353 s\n", 415 | "Iteration: 318 / Delta: 1.107 / Elapsed time: 354 s\n", 416 | "Iteration: 319 / Delta: 1.108 / Elapsed time: 356 s\n", 417 | "Iteration: 320 / Delta: 1.108 / Elapsed time: 357 s\n", 418 | "Iteration: 321 / Delta: 1.108 / Elapsed time: 358 s\n", 419 | "Iteration: 322 / Delta: 1.107 / Elapsed time: 359 s\n", 420 | "Iteration: 323 / Delta: 1.108 / Elapsed time: 360 s\n", 421 | "Iteration: 324 / Delta: 1.108 / Elapsed time: 361 s\n", 422 | "Iteration: 325 / Delta: 1.108 / Elapsed time: 362 s\n", 423 | "Iteration: 326 / Delta: 1.107 / Elapsed time: 363 s\n", 424 | "Iteration: 327 / Delta: 1.107 / Elapsed time: 364 s\n", 425 | "Iteration: 328 / Delta: 1.108 / Elapsed time: 365 s\n", 426 | "Iteration: 329 / Delta: 1.107 / Elapsed time: 367 s\n", 427 | "Iteration: 330 / Delta: 1.108 / Elapsed time: 368 s\n", 428 | "Iteration: 331 / Delta: 1.107 / Elapsed time: 369 s\n", 429 | "Iteration: 332 / Delta: 1.107 / Elapsed time: 370 s\n", 430 | "Iteration: 333 / Delta: 1.107 / Elapsed time: 371 s\n", 431 | "Iteration: 334 / Delta: 1.107 / Elapsed time: 372 s\n", 432 | "Iteration: 335 / Delta: 1.107 / Elapsed time: 373 s\n", 433 | "Iteration: 336 / Delta: 1.107 / Elapsed time: 374 s\n", 434 | "Iteration: 337 / Delta: 1.107 / Elapsed time: 375 s\n", 435 | "Iteration: 338 / Delta: 1.107 / Elapsed time: 377 s\n", 436 | "Iteration: 339 / Delta: 1.107 / Elapsed time: 378 s\n", 437 | "Iteration: 340 / Delta: 1.108 / Elapsed time: 379 s\n", 438 | "Iteration: 341 / Delta: 1.108 / Elapsed time: 380 s\n", 439 | "Iteration: 342 / Delta: 1.108 / Elapsed time: 381 s\n", 440 | "Iteration: 343 / Delta: 1.108 / Elapsed time: 382 s\n", 441 | "Iteration: 344 / Delta: 1.108 / Elapsed time: 383 s\n", 442 | "Iteration: 345 / Delta: 1.108 / Elapsed time: 384 s\n", 443 | "Iteration: 346 / Delta: 1.108 / Elapsed time: 385 s\n", 444 | "Iteration: 347 / Delta: 1.107 / Elapsed time: 386 s\n", 445 | "Iteration: 348 / Delta: 1.108 / Elapsed time: 388 s\n", 446 | "Iteration: 349 / Delta: 1.108 / Elapsed time: 389 s\n", 447 | "Iteration: 350 / Delta: 1.107 / Elapsed time: 390 s\n", 448 | "Iteration: 351 / Delta: 1.108 / Elapsed time: 391 s\n", 449 | "Iteration: 352 / Delta: 1.108 / Elapsed time: 392 s\n", 450 | "Iteration: 353 / Delta: 1.108 / Elapsed time: 393 s\n", 451 | "Iteration: 354 / Delta: 1.108 / Elapsed time: 394 s\n", 452 | "Iteration: 355 / Delta: 1.108 / Elapsed time: 395 s\n", 453 | "Iteration: 356 / Delta: 1.108 / Elapsed time: 396 s\n", 454 | "Iteration: 357 / Delta: 1.107 / Elapsed time: 398 s\n", 455 | "Iteration: 358 / Delta: 1.107 / Elapsed time: 399 s\n", 456 | "Iteration: 359 / Delta: 1.108 / Elapsed time: 400 s\n", 457 | "Iteration: 360 / Delta: 1.107 / Elapsed time: 401 s\n", 458 | "Iteration: 361 / Delta: 1.108 / Elapsed time: 402 s\n", 459 | "Iteration: 362 / Delta: 1.108 / Elapsed time: 403 s\n", 460 | "Iteration: 363 / Delta: 1.108 / Elapsed time: 404 s\n", 461 | "Iteration: 364 / Delta: 1.107 / Elapsed time: 405 s\n", 462 | "Iteration: 365 / Delta: 1.108 / Elapsed time: 406 s\n", 463 | "Iteration: 366 / Delta: 1.107 / Elapsed time: 408 s\n", 464 | "Iteration: 367 / Delta: 1.108 / Elapsed time: 409 s\n", 465 | "Iteration: 368 / Delta: 1.108 / Elapsed time: 410 s\n", 466 | "Iteration: 369 / Delta: 1.107 / Elapsed time: 411 s\n", 467 | "Iteration: 370 / Delta: 1.107 / Elapsed time: 412 s\n", 468 | "Iteration: 371 / Delta: 1.108 / Elapsed time: 413 s\n", 469 | "Iteration: 372 / Delta: 1.107 / Elapsed time: 414 s\n", 470 | "Iteration: 373 / Delta: 1.107 / Elapsed time: 415 s\n", 471 | "Iteration: 374 / Delta: 1.107 / Elapsed time: 416 s\n", 472 | "Iteration: 375 / Delta: 1.107 / Elapsed time: 417 s\n", 473 | "Iteration: 376 / Delta: 1.107 / Elapsed time: 419 s\n", 474 | "Iteration: 377 / Delta: 1.108 / Elapsed time: 420 s\n", 475 | "Iteration: 378 / Delta: 1.108 / Elapsed time: 421 s\n", 476 | "Iteration: 379 / Delta: 1.107 / Elapsed time: 422 s\n", 477 | "Iteration: 380 / Delta: 1.107 / Elapsed time: 423 s\n", 478 | "Iteration: 381 / Delta: 1.108 / Elapsed time: 424 s\n", 479 | "Iteration: 382 / Delta: 1.107 / Elapsed time: 425 s\n", 480 | "Iteration: 383 / Delta: 1.107 / Elapsed time: 426 s\n", 481 | "Iteration: 384 / Delta: 1.108 / Elapsed time: 427 s\n", 482 | "Iteration: 385 / Delta: 1.108 / Elapsed time: 428 s\n", 483 | "Iteration: 386 / Delta: 1.107 / Elapsed time: 430 s\n", 484 | "Iteration: 387 / Delta: 1.107 / Elapsed time: 431 s\n", 485 | "Iteration: 388 / Delta: 1.108 / Elapsed time: 432 s\n", 486 | "Iteration: 389 / Delta: 1.108 / Elapsed time: 433 s\n", 487 | "Iteration: 390 / Delta: 1.107 / Elapsed time: 434 s\n", 488 | "Iteration: 391 / Delta: 1.108 / Elapsed time: 435 s\n", 489 | "Iteration: 392 / Delta: 1.108 / Elapsed time: 436 s\n", 490 | "Iteration: 393 / Delta: 1.108 / Elapsed time: 437 s\n", 491 | "Iteration: 394 / Delta: 1.108 / Elapsed time: 438 s\n", 492 | "Iteration: 395 / Delta: 1.108 / Elapsed time: 440 s\n", 493 | "Iteration: 396 / Delta: 1.108 / Elapsed time: 441 s\n", 494 | "Iteration: 397 / Delta: 1.108 / Elapsed time: 442 s\n", 495 | "Iteration: 398 / Delta: 1.108 / Elapsed time: 443 s\n", 496 | "Iteration: 399 / Delta: 1.107 / Elapsed time: 444 s\n" 497 | ] 498 | } 499 | ], 500 | "source": [ 501 | "# Perform optimization\n", 502 | "# optimizer parameters for ADAM optimizer\n", 503 | "gar_initial = 1\n", 504 | "gar = gar_initial\n", 505 | "beta1 = 0.9\n", 506 | "beta2 = 0.999\n", 507 | "epsilon = 1.e-8\n", 508 | "iter_max = 400\n", 509 | "\n", 510 | "W = torch.tensor([100., 50.],dtype=geo_dtype,device=device)\n", 511 | "momentum = torch.zeros_like(W)\n", 512 | "velocity = torch.zeros_like(W)\n", 513 | "\n", 514 | "W1_history = []\n", 515 | "W2_history = []\n", 516 | "delta_history = []\n", 517 | "\n", 518 | "start_time = time.time()\n", 519 | "for it in range(0,iter_max):\n", 520 | " W.requires_grad_(True)\n", 521 | "\n", 522 | " delta = objective_function(W)\n", 523 | " delta.backward()\n", 524 | "\n", 525 | " with torch.no_grad():\n", 526 | " W_gradient = W.grad\n", 527 | " W.grad = None\n", 528 | "\n", 529 | " W1_history.append(float(W[0].detach().cpu().numpy()))\n", 530 | " W2_history.append(float(W[1].detach().cpu().numpy()))\n", 531 | " delta_history.append(float(delta.detach().cpu().numpy()))\n", 532 | "\n", 533 | " momentum = (beta1*momentum + (1-beta1)*W_gradient)\n", 534 | " velocity = (beta2*velocity + (1-beta2)*(W_gradient**2))\n", 535 | " W += gar*(momentum / (1-beta1**(it+1))) / torch.sqrt((velocity / (1-beta2**(it+1))) + epsilon)\n", 536 | " W[W<50.] = 50.\n", 537 | " W[W>250.] = 250.\n", 538 | " gar -= gar_initial/iter_max\n", 539 | "\n", 540 | " end_time = time.time()\n", 541 | " elapsed_time = end_time - start_time\n", 542 | " print('Iteration:',it,'/ Delta:',int(1000*delta.detach().cpu().numpy())/1000,'/ Elapsed time:',str(int(elapsed_time))+' s')\n", 543 | "\n", 544 | "# Export data\n", 545 | "filename = 'Example5_data.mat'\n", 546 | "ex5_data = {'W1_history':W1_history,'W2_history':W2_history,'delta_history':delta_history}\n", 547 | "scipy.io.savemat(filename,ex5_data)" 548 | ] 549 | } 550 | ], 551 | "metadata": { 552 | "interpreter": { 553 | "hash": "a077222d77dfe082b8f1dd562ad70e458ac2ab76993a0b248ab0476e32e9e8dd" 554 | }, 555 | "kernelspec": { 556 | "display_name": "Python 3.9.7 ('base')", 557 | "language": "python", 558 | "name": "python3" 559 | }, 560 | "language_info": { 561 | "codemirror_mode": { 562 | "name": "ipython", 563 | "version": 3 564 | }, 565 | "file_extension": ".py", 566 | "mimetype": "text/x-python", 567 | "name": "python", 568 | "nbconvert_exporter": "python", 569 | "pygments_lexer": "ipython3", 570 | "version": "3.9.7" 571 | }, 572 | "orig_nbformat": 4 573 | }, 574 | "nbformat": 4, 575 | "nbformat_minor": 2 576 | } 577 | -------------------------------------------------------------------------------- /example/Example0.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "'''\n", 10 | "TORCWA Example0\n", 11 | "Fresnel equation\n", 12 | "\n", 13 | "'''\n", 14 | "# Import\n", 15 | "import numpy as np\n", 16 | "import torch\n", 17 | "from matplotlib import pyplot as plt\n", 18 | "\n", 19 | "import torcwa\n", 20 | "\n", 21 | "# Hardware\n", 22 | "# If GPU support TF32 tensor core, the matmul operation is faster than FP32 but with less precision.\n", 23 | "# If you need accurate operation, you have to disable the flag below.\n", 24 | "torch.backends.cuda.matmul.allow_tf32 = False\n", 25 | "sim_dtype = torch.complex64\n", 26 | "geo_dtype = torch.float32\n", 27 | "device = torch.device('cuda')\n", 28 | "\n", 29 | "# Simulation environment\n", 30 | "# light\n", 31 | "lamb0 = 532. # nm\n", 32 | "azi_ang = 0.*(np.pi/180) # radian\n", 33 | "\n", 34 | "# material\n", 35 | "substrate_eps = 1.46**2\n", 36 | "\n", 37 | "# geometry\n", 38 | "L = [300., 300.] # nm / nm\n", 39 | "torcwa.rcwa_geo.device = device\n", 40 | "torcwa.rcwa_geo.dtype = geo_dtype\n", 41 | "torcwa.rcwa_geo.Lx = L[0]\n", 42 | "torcwa.rcwa_geo.Ly = L[1]\n", 43 | "torcwa.rcwa_geo.nx = 300\n", 44 | "torcwa.rcwa_geo.ny = 300\n", 45 | "torcwa.rcwa_geo.grid()\n", 46 | "torcwa.rcwa_geo.edge_sharpness = 1000.\n", 47 | "\n", 48 | "x_axis = torcwa.rcwa_geo.x.cpu()\n", 49 | "y_axis = torcwa.rcwa_geo.y.cpu()" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 2, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# Generate and perform simulation\n", 59 | "order_N = 7\n", 60 | "order = [order_N,order_N]\n", 61 | "inc_ang = torch.linspace(0.,89.,90,dtype=geo_dtype,device=device)*(np.pi/180)\n", 62 | "\n", 63 | "r_TM = []\n", 64 | "r_TE = []\n", 65 | "t_TM = []\n", 66 | "t_TE = []\n", 67 | "for ia_ind in range(len(inc_ang)):\n", 68 | " inc_ang_now = inc_ang[ia_ind]\n", 69 | " sim = torcwa.rcwa(freq=1/lamb0,order=order,L=L,dtype=sim_dtype,device=device)\n", 70 | " sim.add_input_layer(eps=substrate_eps)\n", 71 | " sim.set_incident_angle(inc_ang=inc_ang_now,azi_ang=azi_ang)\n", 72 | " sim.solve_global_smatrix()\n", 73 | " r_TM.append(sim.S_parameters(orders=[0,0],direction='forward',port='reflection',polarization='pp',ref_order=[0,0]))\n", 74 | " r_TE.append(sim.S_parameters(orders=[0,0],direction='forward',port='reflection',polarization='ss',ref_order=[0,0]))\n", 75 | " t_TM.append(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='pp',ref_order=[0,0]))\n", 76 | " t_TE.append(sim.S_parameters(orders=[0,0],direction='forward',port='transmission',polarization='ss',ref_order=[0,0]))\n", 77 | "\n", 78 | "r_TM = torch.cat(r_TM)\n", 79 | "r_TE = torch.cat(r_TE)\n", 80 | "t_TM = torch.cat(t_TM)\n", 81 | "t_TE = torch.cat(t_TE)" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": 3, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "# Analytic\n", 91 | "n1 = 1.46\n", 92 | "n2 = 1.\n", 93 | "\n", 94 | "R_TM_an = torch.abs( (n1*torch.sqrt(1-(n1/n2*torch.sin(inc_ang.to(sim_dtype)))**2) - n2*torch.cos(inc_ang.to(sim_dtype))) \\\n", 95 | " / (n1*torch.sqrt(1-(n1/n2*torch.sin(inc_ang.to(sim_dtype)))**2) + n2*torch.cos(inc_ang.to(sim_dtype))) )**2\n", 96 | "R_TE_an = torch.abs( (n1*torch.cos(inc_ang.to(sim_dtype)) - n2*torch.sqrt(1-(n1/n2*torch.sin(inc_ang.to(sim_dtype)))**2)) \\\n", 97 | " / (n1*torch.cos(inc_ang.to(sim_dtype)) + n2*torch.sqrt(1-(n1/n2*torch.sin(inc_ang.to(sim_dtype)))**2)) )**2" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 4, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "image/png": "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", 108 | "text/plain": [ 109 | "
" 110 | ] 111 | }, 112 | "metadata": {}, 113 | "output_type": "display_data" 114 | } 115 | ], 116 | "source": [ 117 | "# View spectrum\n", 118 | "plt.plot(180/np.pi*inc_ang.cpu(),R_TM_an.cpu(),'r')\n", 119 | "plt.plot(180/np.pi*inc_ang.cpu(),R_TE_an.cpu(),'b')\n", 120 | "plt.plot(180/np.pi*inc_ang.cpu(),torch.abs(r_TM).cpu()**2,'ro')\n", 121 | "plt.plot(180/np.pi*inc_ang.cpu(),torch.abs(r_TE).cpu()**2,'bo')\n", 122 | "plt.title('Spectrum')\n", 123 | "plt.xlabel('Incident angle (deg.)')\n", 124 | "plt.ylabel('Reflectance')\n", 125 | "plt.grid()" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 5, 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "data": { 135 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHFCAYAAAAOmtghAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAABSY0lEQVR4nO3deVxU5eIG8OcwwLCjgiKyCF7ziqGpUKmFSyVeLTPJtCw1l1umKYileb3lkqXZTWnTrqZxu1l5Myz1RymZC2ZWkrhhaYqyhBFu4MYy8/7+OM7IMAPMgYHZnu/nw4eZ97znzDvzCjy+73vOkYQQAkREREQOwsXaDSAiIiKyJIYbIiIicigMN0RERORQGG6IiIjIoTDcEBERkUNhuCEiIiKHwnBDREREDoXhhoiIiBwKww0RERE5FIYbImqQH374AcOHD0d4eDjUajWCgoLQu3dvzJw509pNw4oVK5CammrtZhCRlUi8/QIRKfV///d/ePDBB9G/f3/8/e9/R3BwMIqKirB//358+umnKCgosGr7oqOjERgYiJ07d1q1HURkHQw3RKRYv379UFhYiF9++QWurq4G27RaLVxcrDsorCTcVFZWQpIko/dBRPaL01JEpNi5c+cQGBhoMhBUDzYRERF44IEHsHHjRnTr1g0eHh7o0KED3nrrLaP9SktL8dxzzyEyMhLu7u4ICQlBUlISrly5YlBPq9Xi7bffRvfu3eHp6YkWLVqgV69e2LRpk/41jx49il27dkGSJEiShIiICADAzp07IUkS/vvf/2LmzJkICQmBWq3Gb7/9hvnz50OSJKN2paamQpIknD592uh9bdmyBT169ICnpyeioqKwZcsW/T5RUVHw9vbGHXfcgf379yv+jImo4fhfFSJSrHfv3nj//fcxffp0PP744+jZsyfc3NxM1s3OzkZSUhLmz5+Ptm3bYt26dUhMTERFRQWee+45AMDVq1fRr18/FBQU4B//+Ae6deuGo0eP4qWXXsLhw4fxzTff6IPHk08+iY8++ggTJ07EwoUL4e7ujp9//lkfPjZu3IgRI0bA398fK1asAACo1WqDNs2ZMwe9e/fGe++9BxcXF7Rp00bxZ3Dw4EHMmTMHc+fOhb+/PxYsWICEhATMmTMH27dvx6uvvgpJkjB79mw88MADyM3Nhaenp+LXIaIGEERECpWUlIi7775bABAAhJubm+jTp49YvHixKCsr09dr3769kCRJZGdnG+w/cOBA4efnJ65cuSKEEGLx4sXCxcVF/PTTTwb1NmzYIACI9PR0IYQQu3fvFgDE3Llz62zfrbfeKvr162dUvmPHDgFA9O3b12jbvHnzhKlfiR988IEAIHJzcw3el6enpygoKNCXZWdnCwAiODhY/76EEOKLL74QAMSmTZvqbDMRWQ6npYhIsYCAAGRmZuKnn37CkiVLMGzYMBw/fhxz5sxB165dUVJSoq9766234rbbbjPYf/To0SgtLcXPP/8MANiyZQuio6PRvXt3VFVV6b8GDRoESZL0a2e++uorAMDUqVMb1f6HH364UfsDQPfu3RESEqJ/HhUVBQDo378/vLy8jMrPnDnT6NckIvNwWoqIGiw2NhaxsbEA5IW5s2fPxvLly7F06VIsXboUANC2bVuj/XRl586dAwD88ccf+O2332qd2tKFpT///BMqlcrkMZUIDg5u1P4A0KpVK4Pn7u7udZZfv3690a9JROZhuCEii3Bzc8O8efOwfPlyHDlyRF9+9uxZo7q6soCAAABAYGAgPD09sXbtWpPHDgwMBAC0bt0aGo0GZ8+ebVRAMbVw2MPDAwBQXl5usEan+igUEdkHTksRkWJFRUUmy48dOwYAaNeunb7s6NGjOHjwoEG9jz/+GL6+vujZsycA4IEHHsDJkycREBCgHw2q/qU722nw4MEAgJUrV9bZPrVajWvXril6T7rXOHTokEH55s2bFR2HiKyPIzdEpNigQYMQGhqKoUOHonPnztBqtcjOzsYbb7wBHx8fJCYm6uu2a9cODz74IObPn4/g4GB89NFHyMjIwGuvvaZfm5KUlITPP/8cffv2xYwZM9CtWzdotVrk5eVh27ZtmDlzJu68807ExcVhzJgxWLRoEf744w888MADUKvVOHDgALy8vDBt2jQAQNeuXfHpp59i/fr16NChAzw8PNC1a9c639OQIUPQqlUr/VlYrq6uSE1NRX5+ftN9kETUJBhuiEixf/7zn/jyyy+xfPlyFBUVoby8HMHBwbjvvvswZ84c/SJaQF54O378eMybNw8nTpxAu3btsGzZMsyYMUNfx9vbG5mZmViyZAlWrVqlP206PDwc9913n35UBZCvIdOzZ0+sWbMGqamp8PT0RJcuXfCPf/xDX2fBggUoKirC3//+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", 136 | "text/plain": [ 137 | "
" 138 | ] 139 | }, 140 | "metadata": {}, 141 | "output_type": "display_data" 142 | } 143 | ], 144 | "source": [ 145 | "# View spectrum\n", 146 | "plt.plot(180/np.pi*inc_ang.cpu(),1-R_TM_an.cpu(),'r')\n", 147 | "plt.plot(180/np.pi*inc_ang.cpu(),1-R_TE_an.cpu(),'b')\n", 148 | "plt.plot(180/np.pi*inc_ang.cpu(),torch.abs(t_TM).cpu()**2,'ro')\n", 149 | "plt.plot(180/np.pi*inc_ang.cpu(),torch.abs(t_TE).cpu()**2,'bo')\n", 150 | "plt.title('Spectrum')\n", 151 | "plt.xlabel('Incident angle (deg.)')\n", 152 | "plt.ylabel('Transmittance')\n", 153 | "plt.grid()" 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "interpreter": { 159 | "hash": "a077222d77dfe082b8f1dd562ad70e458ac2ab76993a0b248ab0476e32e9e8dd" 160 | }, 161 | "kernelspec": { 162 | "display_name": "Python 3.9.7 ('base')", 163 | "language": "python", 164 | "name": "python3" 165 | }, 166 | "language_info": { 167 | "codemirror_mode": { 168 | "name": "ipython", 169 | "version": 3 170 | }, 171 | "file_extension": ".py", 172 | "mimetype": "text/x-python", 173 | "name": "python", 174 | "nbconvert_exporter": "python", 175 | "pygments_lexer": "ipython3", 176 | "version": "3.9.7 (default, Sep 16 2021, 16:59:28) [MSC v.1916 64 bit (AMD64)]" 177 | }, 178 | "orig_nbformat": 4 179 | }, 180 | "nbformat": 4, 181 | "nbformat_minor": 2 182 | } 183 | --------------------------------------------------------------------------------