├── .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 | 
107 | 
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 | 
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 |
--------------------------------------------------------------------------------