├── .github └── workflows │ └── python-publish.yml ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── example_gym.py ├── example_inc_tmm.py ├── example_tmm.py ├── meta.yaml ├── pyproject.toml ├── requirements.txt ├── tests ├── test_coherent.py └── test_incoherent.py └── tmm_fast ├── __init__.py ├── gym_multilayerthinfilm ├── LICENSE ├── README.md ├── __init__.py ├── gym_class.py ├── gym_environment_example.py ├── gym_multilayerthinfilm.yml └── utils.py ├── materials ├── nAu.txt ├── nNb2O5.txt └── nSiO2.txt ├── misc └── tmm_structure.svg ├── plotting_helper.py ├── tmm_fast_torch.py ├── vectorized_incoherent_tmm.py └── vectorized_tmm_dispersive_multistack.py /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package tp PyPi 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy_ubuntu: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Set up Python 26 | uses: actions/setup-python@v3 27 | with: 28 | python-version: '3.x' 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install build 33 | - name: Build package 34 | run: python -m build 35 | - name: Publish package 36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | 41 | # deploy_windows: 42 | # runs-on: windows-latest 43 | 44 | # steps: 45 | # - uses: actions/checkout@v3 46 | # - name: Set up Python 47 | # uses: actions/setup-python@v3 48 | # with: 49 | # python-version: '3.x' 50 | # - name: Install dependencies 51 | # run: | 52 | # python -m pip install --upgrade pip 53 | # pip install build 54 | # - name: Build package 55 | # run: python -m build 56 | # - name: Publish package 57 | # uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 58 | # with: 59 | # user: __token__ 60 | # password: ${{ secrets.PYPI_API_TOKEN }} 61 | 62 | # deploy_macos: 63 | 64 | # runs-on: macos-latest 65 | 66 | # steps: 67 | # - uses: actions/checkout@v3 68 | # - name: Set up Python 69 | # uses: actions/setup-python@v3 70 | # with: 71 | # python-version: '3.x' 72 | # - name: Install dependencies 73 | # run: | 74 | # python -m pip install --upgrade pip 75 | # pip install build 76 | # - name: Build package 77 | # run: python -m build 78 | # - name: Publish package 79 | # uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 80 | # with: 81 | # user: __token__ 82 | # password: ${{ secrets.PYPI_API_TOKEN }} 83 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "githubPullRequests.ignoredPullRequestBranches": [ 3 | "main" 4 | ] 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MLResearchAtOSRAM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tmm_fast 2 | 3 | tmm_fast or transfer-matrix-method_fast is a lightweight package to speed up optical planar multilayer thin-film device computation. 4 | Typically, one is interested in computing the Reflection and/or Transmission of light through a multilayer thin-film depending on the 5 | wavelength and angle of incidence of the incoming light. The package is build on the [original tmm package](https://github.com/sbyrnes321/tmm) from sjbyrnes but quite a lot faster. Depending on the number of layers, wavelength range and angular range speed-ups of ~100x are possible. The physics behind the transfer matrix method can be studied in any textbook on optical devices or in [Multilayer optical calculations](https://arxiv.org/abs/1603.02720) 6 | from Steven J. Byrnes. 7 | More detailed information about the package and its applications can be found in [TMM-Fast: A Transfer Matrix Computation Package for Multilayer Thin-Film Optimization](https://arxiv.org/abs/2111.13667). 8 | 9 | ![overview](https://user-images.githubusercontent.com/83709614/169793015-0e8b214d-b6f2-4da2-9030-fd8a1ed5ef71.svg)
10 | Figure 1: Overview about what you can do with this package. 11 | 12 | 13 | ## Getting Started 14 | 15 | To get a local copy up and running follow these steps: 16 | 17 | ### Installation 18 | 19 | `tmm-fast` package requires `pytorch`, therefore it is better to install it first following [official instructions](https://pytorch.org/get-started/locally/). 20 | 21 | Stable version from [pipy.org](https://pypi.org/project/tmm-fast/): 22 | 23 | ```sh 24 | pip install tmm-fast 25 | ``` 26 | 27 | Latest version from [github.com](https://github.com/MLResearchAtOSRAM/tmm_fast): 28 | 29 | ```sh 30 | pip install git+https://github.com/MLResearchAtOSRAM/tmm_fast 31 | ``` 32 | 33 | ## Unified functionality of tmm_fast: Sponge PyTorch functionality for free 34 | Parallelized computation of reflection and transmission for coherent light spectra that traverse 35 | a bunch of multilayer thin-films with dispersive materials. 36 | This package is essentially build on Pytorch and its related functionalities such as GPU accelerations and Autograd. 37 | It naturally allows for: 38 | - GPU accelerated computations 39 | - To compute gradients regarding the multilayer thin-film (i.e. N, T) thanks to Pytorch Autograd 40 | - Vectorized computations, i.e. using Einstein summation convention 41 | 42 | In general, tmm_fast is a lightweight package to speed up the computations of reflection and transmission of optical planar multilayer thin-films by vectorization regarding 43 | - a set of multilayer thin-films consisting of various layers of particular material and thickness, 44 | - a set of wavelengths, and 45 | - a set of incident angles. 46 | 47 | ### For old guards: Numpy is fully supported 48 | All of the inputs can also be a numpy array format instead of torch tensors. 49 | However, all internal computations are processed via PyTorch and thus the output data is converted back to numpy arrays again. 50 | Hence, the use of numpy input may increase computation time due to data type conversions. 51 | 52 | ### Benefits and conducted sanity checks, backgrounds 53 | Depending on the number of thin films an their number of layers as well as the considered wavelengths that irradiate the thin film under particular angles of incident, the computation time can be decreased by 2-3 orders of magnitude. 54 | This claim is supported by several cross-checks (https://arxiv.org/abs/2111.13667), conducted with the code provided by Steven J. Byrnes (https://arxiv.org/abs/1603.02720). Of course, the checks covered both, computational time and physical outputs. 55 | 56 | The physics behind the transfer matrix method can be studied in any textbook on optical devices or related papers, e.g. 57 | - Chapter on thin films in Microphotonics (http://www.photonics.intec.ugent.be/download/ocs129.pdf) by Dries Van Thourhout, Roel Baets (UGent) and Heidi Ottevaere (VUB) 58 | - Multilayer optical computations (https://arxiv.org/abs/1603.02720) by Steven J. Byrnes 59 | - The Fresnel Coefficient of Thin Film Multilayer Using Transfer Matrix Method (https://iopscience.iop.org/article/10.1088/1757-899X/518/3/032026) by Zahraa Hummam Mohammed 60 | 61 | # gym-multilayerthinfilm 62 | 63 | The proposed OpenAI/Farama-Foundation gymnasium environment utilizes the parallelized transfer-matrix method (TMM-Fast) to implement the optimization of multi-layer thin films as parameterized Markov decision processes. A very intuitive example is provided in example.py. 64 | Whereas the contained physical methods are well-studied and known since decades, the contribution of this code lies the transfer to an OpenAI/Farama-Foundation gymnasium environment. The intention is to enable AI researchers without optical expertise to solve the corresponding parameterized Markov decision processes. Due to their structure, the solution of such problems is still an active field of research in the AI community.
65 | The publication [Parameterized Reinforcement learning for Optical System Optimization](https://iopscience.iop.org/article/10.1088/1361-6463/abfddb) used a related environment. 66 | 67 | ## Getting started 68 | To get started you can do the example py-files for tmm (example_tmm.py) or the gymnasium environment (example_gym.py)! 69 | 70 | ## Multi-layer thin films meet parameterized reinforcement learning 71 | Reinforcement learning is an area of machine learning concerned with how intelligent agents ought to take actions in an environment in order to maximize the notion of reward. The code to be published implements such an environment for the optimization of multi-layer thin films. 72 | In principle, the proposed code allows to execute actions taken by an agent. These actions determine which material and with which thickness to stack next, thereby consecutively forming a multi-layer thin film as illustrated in Figure 1. Such a multilayer thin-film exhibits optical characteristics. By comparison between the actual and user-defined desired characteristics, a notion of numeric reward is computed based on which the agent learns to distinguish between good and bad design choices. Due to its physical and mathematical structure, the optimization of multi-layer thin film remains a challenging and thus still active field of research in the scientific community. As such it gained recent attention in many publications. Therefore, naturally the need for a standardized environment arises to make the corresponding research more trustful, comparable and consistent. 73 | 74 | ![image](https://user-images.githubusercontent.com/83709614/127179171-bc7e8fe5-bd83-4125-a84f-12a9e16c3150.png)
75 | Figure 2: Principal idea of an OpenAI/Farama-Foundation gymnasium environment. The agent takes an action that specifies the material and thickness of the layer to stack next. The environment implements the multi-layer thin film generation as consecutive conduction of actions and assigns a reward to a proposed multi-layer thin film based on how close the actual (solid orange line) fulfils a desired (dashed orange line) characteristic. The made experience is used to adapt the taken actions made in order to increase the reward and thus generate more and more sophisticated multi-layer thin films. 76 | 77 | ### Description of key features 78 | The environment can include
79 | • cladding of the multi-layer thin film (e.g. substrate and ambient materials),
80 | • dispersive and dissipative materials,
81 | • spectral and angular optical behavior of multi-layer thin films (See figure 3),
82 | • … and many more.
83 | 84 | The environment class allows to
85 | • conduct so-called parameterized actions (See publication) that define a multi-layer thin film,
86 | • evaluate the generated thin film given a desired optical response, and
87 | • render the results (See figure 3).
88 | 89 | In general, the comprehensive optimization of multi-layer thin films in regards of optical response encompasses
90 | • the number of layers (integer),
91 | • the thickness of each layer (float),
92 | • the material of each layer (categorical, integer).
93 | 94 | ![image](https://user-images.githubusercontent.com/83709614/127179200-16aaf611-ad17-4082-a47f-d933ba7cbc83.png)
95 | Figure 3: Rendered output of the environment. Reflectivity (left) over angle of incidence and spectrum of a multi-layer thin film (right). Here, the stack features four layers and each layer’s material was chosen from a set of eight alternatives. The reward is computed based on a desired reflectivity, which is one for each angle and wavelength, but not displayed in this figure. 96 | 97 | 98 | # Citing 99 | If you use the code from this repository for your projects, please cite
100 | [TMM-Fast: A Transfer Matrix Computation Package for Multilayer Thin-Film Optimization](https://doi.org/10.1364/JOSAA.450928) or/and
101 | [Parameterized reinforcement learning for optical system optimization](https://iopscience.iop.org/article/10.1088/1361-6463/abfddb) in your publications. 102 | -------------------------------------------------------------------------------- /example_gym.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from pathlib import Path 4 | 5 | import tmm_fast.gym_multilayerthinfilm as mltf 6 | 7 | # Material specifications 8 | # Pathes were material txt-files are stored are gathered in a list 9 | path = str(Path(__file__).parent) 10 | pathAu = path+'\\tmm_fast\\materials\\nAu.txt' 11 | pathNb2O5 = path+'\\tmm_fast\\materials\\nNb2O5.txt' 12 | pathSiO2 = path+'\\tmm_fast\\materials\\nSiO2.txt' 13 | 14 | material_path_list = [pathAu, pathNb2O5, pathSiO2] 15 | 16 | # Specification of operation mode as well as angular and spectral range of interest 17 | 18 | mode = 'reflectivity' # 'transmittivity' or 'reflectivity' 19 | maximum_number_of_layers = 10 20 | angle_min = 0 # ° 21 | angle_max = 90 # ° 22 | lambda_min = 400 # nm 23 | lambda_max = 700 # nm 24 | 25 | # Definition of the target reflectivity for each angle and wavelength (pixelwise as an array) 26 | target_array = 0.5 * np.ones((int(angle_max - angle_min), int(lambda_max - lambda_min))) 27 | 28 | 29 | wl = np.linspace(lambda_min, lambda_max, int(lambda_max - lambda_min)) * 1e-9 30 | angle = np.linspace(angle_min, angle_max, int(angle_max - angle_min)) 31 | target = {'direction': angle, 'spectrum': wl, 'target': target_array, 'mode': mode} 32 | 33 | N = mltf.get_N(material_path_list, lambda_min, lambda_max, points=int(lambda_max - lambda_min), complex_n=True) 34 | N = np.vstack((N, np.ones((1, N.shape[1])))) 35 | 36 | # Creation of the environment given the above information 37 | env = mltf.MultiLayerThinFilm(N, maximum_number_of_layers, target) 38 | 39 | env.reset() 40 | 41 | # By default the multilayer thin film is cladded by vacuum of infinite thickness. 42 | # Well, let's assume that the light injection layer is actually air (which is very close to vacuum), 43 | # but the ambient consists of gold (Au) of infinite thickness. In case that the ambient consisits of more stacked 44 | # materials, we can just expand the list properly! 45 | # The procedure remains the same for the substrate of course. 46 | 47 | #ambient: 48 | ambient_material_list = [2] 49 | ambient_thickness_list = [np.inf] 50 | # The create_stack-method forms a dictionary that defines the ambient: 51 | _, _, ambient_dict = env.create_stack(ambient_material_list, ambient_thickness_list) 52 | env.set_cladding(ambient=ambient_dict) 53 | # We might get warned, if the refractive indexes in the ambient are non-real! 54 | 55 | 56 | # In the following, a particular multilayer thin film is constructed inbetween the aforementioned cladding 57 | # via consecutive layer stacking. Here, the thin film consists of tow layers (Nb2O5 and SiO2) of thicknesses 10 nm each: 58 | layer_material_list = [2, 3] 59 | for layer in layer_material_list: 60 | # Execute steps to form multilayer thin film via layer stacking: 61 | env.step(env.create_action(layer, thickness=10e-9)) 62 | # And another three random layers: 63 | env.step(env.action_space.sample()) 64 | env.step(env.action_space.sample()) 65 | # For the last step, we read out the state-list as well as the reward and done-flag. 66 | # Note that the read-out reward is only non-zero if done==True in case that env.sparse_reward is True, therefore we set: 67 | env.sparse_reward = False 68 | [simulation, n, d, one_hot_status], reward, done, _ = env.step(env.action_space.sample()) 69 | 70 | # Finally, we render the target that was provided above as well as the current state of the environment 71 | # Namely, the state is defined by the currently formed thin film as well as the corresponding optical behavior 72 | env.render_target() 73 | env.render() 74 | print(':)') 75 | -------------------------------------------------------------------------------- /example_inc_tmm.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from tmm_fast import inc_tmm as inc_tmm_fast 4 | import matplotlib.pyplot as plt 5 | 6 | np.random.seed(111) 7 | torch.manual_seed(111) 8 | 9 | n_wl = 75 10 | n_th = 45 11 | pol = 's' 12 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 13 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 14 | num_layers = 6 15 | num_stacks = 2 16 | mask = [[1, 2], [4]] 17 | imask = ['i', 'c', 'c', 'i', 'c', 'i'] 18 | 19 | #create m 20 | M = torch.ones((num_stacks, num_layers, wl.shape[0]), dtype=torch.complex128) 21 | # for i in range(1, M.shape[1]-1): 22 | # if np.mod(i, 2) == 1: 23 | # M[:, i, :] *= np.random.uniform(1,3,[1])[0] 24 | # M[:, i, :] += .05j 25 | # else: 26 | # M[:, i, :] *= np.random.uniform(1,3,[1])[0] 27 | # M[:, i, :] += .02j 28 | 29 | M[:, 1] = 2.2 + .0j 30 | M[:, 2] = 1.3 + .0j 31 | M[:, 3] = 2.2 + .05j 32 | M[:, 4] = 1.3 + .2j 33 | 34 | #create t 35 | max_t = 350 * (10**(-9)) 36 | min_t = 10 * (10**(-9)) 37 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 38 | 39 | T[:, 0] = np.inf 40 | T[:, 1] = 250e-9 41 | T[:, 2] = 2000e-9 42 | T[:, 3] = 150e-9 43 | T[:, -1] = np.inf 44 | 45 | T = torch.from_numpy(T) 46 | O_fast = inc_tmm_fast(pol, M, T, mask, theta, wl, device='cpu') 47 | 48 | fig, ax = plt.subplots(2,1) 49 | cbar = ax[0].imshow(O_fast['R'][0].numpy(), aspect='auto') 50 | ax[0].set_xlabel('wavelength') 51 | ax[0].set_ylabel('angle of incidence') 52 | plt.colorbar(cbar, ax=ax[0]) 53 | ax[0].title.set_text('Reflectivity') 54 | cbar = ax[1].imshow(O_fast['T'][0].numpy(), aspect='auto') 55 | plt.colorbar(cbar, ax=ax[1]) 56 | ax[1].title.set_text('Transmissivity') 57 | ax[1].set_xlabel('wavelength') 58 | ax[1].set_ylabel('angle of incidence') 59 | fig.tight_layout(pad=2.) 60 | 61 | plt.show() 62 | a=0 63 | -------------------------------------------------------------------------------- /example_tmm.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from tmm_fast import coh_tmm as tmm 4 | 5 | wl = np.linspace(400, 1200, 800) * (10**(-9)) 6 | theta = np.linspace(0, 45, 45) * (np.pi/180) 7 | mode = 'T' 8 | num_layers = 4 9 | num_stacks = 128 10 | 11 | #create m 12 | M = np.ones((num_stacks, num_layers, wl.shape[0])) 13 | for i in range(1, M.shape[1]-1): 14 | if np.mod(i, 2) == 1: 15 | M[:, i, :] *= 1.46 16 | else: 17 | M[:, i, :] *= 2.56 18 | 19 | #create t 20 | max_t = 150 * (10**(-9)) 21 | min_t = 10 * (10**(-9)) 22 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 23 | T[:, 0] = np.inf 24 | T[:, -1] = np.inf 25 | 26 | #tmm: 27 | O = tmm('s', M, T, theta, wl, device='cpu') 28 | 29 | print(':)') 30 | -------------------------------------------------------------------------------- /meta.yaml: -------------------------------------------------------------------------------- 1 | {% set name = tmm_fast %} 2 | {% set version = "0.1" %} 3 | 4 | package: 5 | name: {{ name }} 6 | version: {{ version }} 7 | 8 | source: 9 | url: https://pypi.io/packages/source/i/imagesize/imagesize-{{ version }}.tar.gz 10 | sha256: f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5 11 | 12 | build: 13 | noarch: python 14 | number: 0 15 | script: python -m pip install --no-deps --ignore-installed . 16 | 17 | requirements: 18 | host: 19 | - python 20 | - pip 21 | - pytorch 22 | run: 23 | - python 24 | 25 | test: 26 | imports: 27 | - imagesize 28 | 29 | about: 30 | home: https://github.com/shibukawa/imagesize_py 31 | license: MIT 32 | summary: 'Getting image size from png/jpeg/jpeg2000/gif file' 33 | description: | 34 | This module analyzes jpeg/jpeg2000/png/gif image header and 35 | return image size. 36 | dev_url: https://github.com/shibukawa/imagesize_py 37 | doc_url: https://pypi.python.org/pypi/imagesize 38 | doc_source_url: https://github.com/shibukawa/imagesize_py/blob/master/README.rst -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "setuptools-scm"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tmm_fast" 7 | version = "0.2.1" 8 | authors = [ 9 | {name = "Alexander Luce", email = "alexander.luce@ams-osram.com"}, 10 | {name = "Heribert Wankerl"}, 11 | ] 12 | description = 'tmm_fast is a lightweight package to speed up optical planar multilayer thin-film device computation.' 13 | readme = "README.md" 14 | requires-python = ">=3.7" 15 | keywords = ["one", "two"] 16 | license = {text = "MIT"} 17 | classifiers = [ 18 | "Programming Language :: Python :: 3", 19 | ] 20 | dependencies = [ 21 | "numpy", 22 | "torch>1.9", 23 | "matplotlib", 24 | "gymnasium", 25 | ] 26 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | torch>=1.9 3 | Matplotlib 4 | Seaborn 5 | Gymnasium -------------------------------------------------------------------------------- /tests/test_coherent.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from tmm_fast import coh_tmm as coh_tmm_fast 4 | import matplotlib.pyplot as plt 5 | 6 | from tmm import coh_tmm 7 | 8 | 9 | def test_input_output_medium(): 10 | np.random.seed(111) 11 | torch.manual_seed(111) 12 | n_wl = 65 13 | n_th = 45 14 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 15 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 16 | num_layers = 2 17 | num_stacks = 2 18 | 19 | #create m 20 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 21 | M[:, 0] = 2.5 22 | M[:, 0] = 1.3 23 | 24 | #create t 25 | max_t = 150 * (10**(-9)) 26 | min_t = 10 * (10**(-9)) 27 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 28 | 29 | T[:, 0] = np.inf 30 | T[:, 1] = np.inf 31 | 32 | T = torch.from_numpy(T) 33 | O_fast_s = coh_tmm_fast('s', M, T, theta, wl, device='cpu') 34 | O_fast_p = coh_tmm_fast('p', M, T, theta, wl, device='cpu') 35 | 36 | R_tmm_s = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 37 | R_tmm_p = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 38 | T_tmm_s = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 39 | T_tmm_p = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 40 | 41 | for h in range(num_stacks): 42 | for i, t in enumerate(theta.tolist()): 43 | for j, w in enumerate(wl.tolist()): 44 | res_s = coh_tmm('s', M[0][:, j].tolist(), T[h].tolist(), t, w) 45 | res_p = coh_tmm('p', M[0][:, j].tolist(), T[h].tolist(), t, w) 46 | R_tmm_s[h, i, j] = res_s['R'] 47 | R_tmm_p[h, i, j] = res_p['R'] 48 | T_tmm_s[h, i, j] = res_s['T'] 49 | T_tmm_p[h, i, j] = res_p['T'] 50 | 51 | if torch.cuda.is_available(): 52 | O_fast_s_gpu = coh_tmm_fast('s', M, T, theta, wl, device='cuda') 53 | O_fast_p_gpu = coh_tmm_fast('p', M, T, theta, wl, device='cuda') 54 | 55 | assert O_fast_s_gpu, 'gpu computation not available' 56 | torch.testing.assert_close(R_tmm_s, O_fast_s_gpu['R'], rtol=1e-6, atol=1e-6) 57 | torch.testing.assert_close(R_tmm_p, O_fast_p_gpu['R'], rtol=1e-6, atol=1e-6) 58 | torch.testing.assert_close(T_tmm_s, O_fast_s_gpu['T'], rtol=1e-6, atol=1e-6) 59 | torch.testing.assert_close(T_tmm_p, O_fast_p_gpu['T'], rtol=1e-6, atol=1e-6) 60 | 61 | torch.testing.assert_close(R_tmm_s, O_fast_s['R'], rtol=1e-6, atol=1e-6) 62 | torch.testing.assert_close(R_tmm_p, O_fast_p['R'], rtol=1e-6, atol=1e-6) 63 | torch.testing.assert_close(T_tmm_s, O_fast_s['T'], rtol=1e-6, atol=1e-6) 64 | torch.testing.assert_close(T_tmm_p, O_fast_p['T'], rtol=1e-6, atol=1e-6) 65 | 66 | # check dtypes, it appears that pytorch uses float16 67 | # at some point in the computation 68 | # torch.testing.assert_close(O_fast_s['T'][0], T_tmm_s) 69 | 70 | 71 | def test_basic_coherent_stack(): 72 | np.random.seed(111) 73 | torch.manual_seed(111) 74 | n_wl = 65 75 | n_th = 45 76 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 77 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 78 | num_layers = 8 79 | num_stacks = 3 80 | 81 | #create m 82 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 83 | for i in range(1, M.shape[1]-1): 84 | if np.mod(i, 2) == 1: 85 | M[:, i, :] *= np.random.uniform(0, 3, [1])[0] 86 | else: 87 | M[:, i, :] *= np.random.uniform(0, 3, [1])[0] 88 | 89 | #create t 90 | max_t = 150 * (10**(-9)) 91 | min_t = 10 * (10**(-9)) 92 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 93 | 94 | T[:, 0] = np.inf 95 | T[:, -1] = np.inf 96 | 97 | T = torch.from_numpy(T) 98 | O_fast_s = coh_tmm_fast('s', M, T, theta, wl, device='cpu') 99 | O_fast_p = coh_tmm_fast('p', M, T, theta, wl, device='cpu') 100 | 101 | R_tmm_s = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 102 | R_tmm_p = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 103 | T_tmm_s = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 104 | T_tmm_p = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 105 | 106 | for h in range(num_stacks): 107 | for i, t in enumerate(theta.tolist()): 108 | for j, w in enumerate(wl.tolist()): 109 | res_s = coh_tmm('s', M[0][:, j].tolist(), T[h].tolist(), t, w) 110 | res_p = coh_tmm('p', M[0][:, j].tolist(), T[h].tolist(), t, w) 111 | R_tmm_s[h, i, j] = res_s['R'] 112 | R_tmm_p[h, i, j] = res_p['R'] 113 | T_tmm_s[h, i, j] = res_s['T'] 114 | T_tmm_p[h, i, j] = res_p['T'] 115 | 116 | if torch.cuda.is_available(): 117 | O_fast_s_gpu = coh_tmm_fast('s', M, T, theta, wl, device='cuda') 118 | O_fast_p_gpu = coh_tmm_fast('p', M, T, theta, wl, device='cuda') 119 | 120 | assert O_fast_s_gpu, 'gpu computation not available' 121 | torch.testing.assert_close(R_tmm_s, O_fast_s_gpu['R'], rtol=1e-6, atol=1e-6) 122 | torch.testing.assert_close(R_tmm_p, O_fast_p_gpu['R'], rtol=1e-6, atol=1e-6) 123 | torch.testing.assert_close(T_tmm_s, O_fast_s_gpu['T'], rtol=1e-6, atol=1e-6) 124 | torch.testing.assert_close(T_tmm_p, O_fast_p_gpu['T'], rtol=1e-6, atol=1e-6) 125 | 126 | torch.testing.assert_close(R_tmm_s, O_fast_s['R'], rtol=1e-6, atol=1e-6) 127 | torch.testing.assert_close(R_tmm_p, O_fast_p['R'], rtol=1e-6, atol=1e-6) 128 | torch.testing.assert_close(T_tmm_s, O_fast_s['T'], rtol=1e-6, atol=1e-6) 129 | torch.testing.assert_close(T_tmm_p, O_fast_p['T'], rtol=1e-6, atol=1e-6) 130 | 131 | 132 | 133 | def test_absorbing_coherent_stack(): 134 | np.random.seed(111) 135 | torch.manual_seed(111) 136 | n_wl = 65 137 | n_th = 45 138 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 139 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 140 | num_layers = 8 141 | num_stacks = 3 142 | 143 | #create m 144 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 145 | for i in range(1, M.shape[1]-1): 146 | if np.mod(i, 2) == 1: 147 | M[:, i, :] *= np.random.uniform(0,3,[1])[0] 148 | M[:, i, :] += np.random.uniform(0, 1, [1])[0]*1j 149 | else: 150 | M[:, i, :] *= np.random.uniform(0,3,[1])[0] 151 | M[:, i, :] += np.random.uniform(0, 1, [1])[0]*1j 152 | 153 | #create t 154 | max_t = 150 * (10**(-9)) 155 | min_t = 10 * (10**(-9)) 156 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 157 | 158 | T[:, 0] = np.inf 159 | T[:, -1] = np.inf 160 | 161 | T = torch.from_numpy(T) 162 | O_fast_s = coh_tmm_fast('s', M, T, theta, wl, device='cpu') 163 | O_fast_p = coh_tmm_fast('p', M, T, theta, wl, device='cpu') 164 | 165 | R_tmm_s = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 166 | R_tmm_p = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 167 | T_tmm_s = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 168 | T_tmm_p = torch.zeros((num_stacks, n_th, n_wl), dtype=torch.double) 169 | 170 | for h in range(num_stacks): 171 | for i, t in enumerate(theta.tolist()): 172 | for j, w in enumerate(wl.tolist()): 173 | res_s = coh_tmm('s', M[0][:, j].tolist(), T[h].tolist(), t, w) 174 | res_p = coh_tmm('p', M[0][:, j].tolist(), T[h].tolist(), t, w) 175 | R_tmm_s[h, i, j] = res_s['R'] 176 | R_tmm_p[h, i, j] = res_p['R'] 177 | T_tmm_s[h, i, j] = res_s['T'] 178 | T_tmm_p[h, i, j] = res_p['T'] 179 | 180 | if torch.cuda.is_available(): 181 | O_fast_s_gpu = coh_tmm_fast('s', M, T, theta, wl, device='cuda') 182 | O_fast_p_gpu = coh_tmm_fast('p', M, T, theta, wl, device='cuda') 183 | 184 | assert O_fast_s_gpu, 'gpu computation not available' 185 | torch.testing.assert_close(R_tmm_s, O_fast_s_gpu['R'], rtol=1e-6, atol=1e-6) 186 | torch.testing.assert_close(R_tmm_p, O_fast_p_gpu['R'], rtol=1e-6, atol=1e-6) 187 | torch.testing.assert_close(T_tmm_s, O_fast_s_gpu['T'], rtol=1e-6, atol=1e-6) 188 | torch.testing.assert_close(T_tmm_p, O_fast_p_gpu['T'], rtol=1e-6, atol=1e-6) 189 | 190 | torch.testing.assert_close(R_tmm_s, O_fast_s['R'], rtol=1e-6, atol=1e-6) 191 | torch.testing.assert_close(R_tmm_p, O_fast_p['R'], rtol=1e-6, atol=1e-6) 192 | torch.testing.assert_close(T_tmm_s, O_fast_s['T'], rtol=1e-6, atol=1e-6) 193 | torch.testing.assert_close(T_tmm_p, O_fast_p['T'], rtol=1e-6, atol=1e-6) 194 | 195 | 196 | if __name__ == '__main__': 197 | test_input_output_medium() 198 | test_basic_coherent_stack() 199 | test_absorbing_coherent_stack() -------------------------------------------------------------------------------- /tests/test_incoherent.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from tmm_fast import inc_tmm as inc_tmm_fast 4 | import matplotlib.pyplot as plt 5 | 6 | from tmm import inc_tmm 7 | 8 | def test_incoherent_input_output_medium(): 9 | n_wl = 65 10 | n_th = 45 11 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 12 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 13 | num_layers = 2 14 | num_stacks = 2 15 | mask = [] 16 | 17 | #create m 18 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 19 | for i in range(1, M.shape[1]-1): 20 | if np.mod(i, 2) == 1: 21 | M[:, i, :] *= 1.46 22 | else: 23 | M[:, i, :] *= 2.56 24 | 25 | #create t 26 | max_t = 150 * (10**(-9)) 27 | min_t = 10 * (10**(-9)) 28 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 29 | 30 | T[:, 0] = np.inf 31 | T[:, 1] = np.inf 32 | 33 | T = torch.from_numpy(T) 34 | O_fast_s = inc_tmm_fast('s', M, T, mask, theta, wl, device='cpu') 35 | O_fast_p = inc_tmm_fast('p', M, T, mask, theta, wl, device='cpu') 36 | 37 | R_tmm_s = torch.zeros((n_th, n_wl)) 38 | R_tmm_p = torch.zeros((n_th, n_wl)) 39 | T_tmm_s = torch.zeros((n_th, n_wl)) 40 | T_tmm_p = torch.zeros((n_th, n_wl)) 41 | 42 | T_list = T[0].tolist() 43 | 44 | for i, t in enumerate(theta.tolist()): 45 | for j, w in enumerate(wl.tolist()): 46 | res_s = inc_tmm('s', M[0][:, j].tolist(), T_list, ['i', 'i'], t, w) 47 | res_p = inc_tmm('p', M[0][:, j].tolist(), T_list, ['i', 'i'], t, w) 48 | R_tmm_s[i, j] = res_s['R'] 49 | R_tmm_p[i, j] = res_p['R'] 50 | T_tmm_s[i, j] = res_s['T'] 51 | T_tmm_p[i, j] = res_p['T'] 52 | 53 | if torch.cuda.is_available(): 54 | O_fast_s_gpu = inc_tmm_fast('s', M, T, mask, theta, wl, device='cuda') 55 | O_fast_p_gpu = inc_tmm_fast('p', M, T, mask, theta, wl, device='cuda') 56 | 57 | assert O_fast_s_gpu, 'gpu computation not availabla' 58 | assert torch.allclose(R_tmm_s, O_fast_s_gpu['R']) 59 | assert torch.allclose(R_tmm_p, O_fast_p_gpu['R']) 60 | assert torch.allclose(T_tmm_s, O_fast_s_gpu['T']) 61 | assert torch.allclose(T_tmm_p, O_fast_p_gpu['T']) 62 | 63 | assert torch.allclose(R_tmm_s, O_fast_s['R']) 64 | assert torch.allclose(R_tmm_p, O_fast_p['R']) 65 | assert torch.allclose(T_tmm_s, O_fast_s['T']) 66 | assert torch.allclose(T_tmm_p, O_fast_p['T']) 67 | 68 | 69 | def test_fully_incoherent_stack(): 70 | n_wl = 65 71 | n_th = 45 72 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 73 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 74 | num_layers = 5 75 | num_stacks = 2 76 | mask = [] 77 | 78 | #create m 79 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 80 | for i in range(1, M.shape[1]-1): 81 | if np.mod(i, 2) == 1: 82 | M[:, i, :] *= 1.46 83 | else: 84 | M[:, i, :] *= 2.56 85 | 86 | #create t 87 | max_t = 150000 * (10**(-9)) 88 | min_t = 10000 * (10**(-9)) 89 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 90 | 91 | T[:, 0] = np.inf 92 | T[:, 1] = 10000e-9 93 | T[:, 2] = 2000e-9 94 | T[:, 3] = 5000e-9 95 | T[:, -1] = np.inf 96 | 97 | T = torch.from_numpy(T) 98 | O_fast_s = inc_tmm_fast('s', M, T, mask, theta, wl, device='cpu') 99 | O_fast_p = inc_tmm_fast('p', M, T, mask, theta, wl, device='cpu') 100 | 101 | R_tmm_s = torch.zeros((n_th, n_wl)) 102 | R_tmm_p = torch.zeros((n_th, n_wl)) 103 | T_tmm_s = torch.zeros((n_th, n_wl)) 104 | T_tmm_p = torch.zeros((n_th, n_wl)) 105 | 106 | T_list = T[0].tolist() 107 | 108 | for i, t in enumerate(theta.tolist()): 109 | for j, w in enumerate(wl.tolist()): 110 | res_s = inc_tmm('s', M[0][:, j].tolist(), T_list, ['i', 'i', 'i', 'i', 'i'], t, w) 111 | res_p = inc_tmm('p', M[0][:, j].tolist(), T_list, ['i', 'i', 'i', 'i', 'i'], t, w) 112 | R_tmm_s[i, j] = res_s['R'] 113 | R_tmm_p[i, j] = res_p['R'] 114 | T_tmm_s[i, j] = res_s['T'] 115 | T_tmm_p[i, j] = res_p['T'] 116 | 117 | if torch.cuda.is_available(): 118 | O_fast_s_gpu = inc_tmm_fast('s', M, T, mask, theta, wl, device='cuda') 119 | O_fast_p_gpu = inc_tmm_fast('p', M, T, mask, theta, wl, device='cuda') 120 | 121 | assert O_fast_s_gpu, 'gpu computation not availabla' 122 | assert torch.allclose(R_tmm_s, O_fast_s_gpu['R']) 123 | assert torch.allclose(R_tmm_p, O_fast_p_gpu['R']) 124 | assert torch.allclose(T_tmm_s, O_fast_s_gpu['T']) 125 | assert torch.allclose(T_tmm_p, O_fast_p_gpu['T']) 126 | 127 | assert torch.allclose(R_tmm_s, O_fast_s['R']) 128 | assert torch.allclose(R_tmm_p, O_fast_p['R']) 129 | assert torch.allclose(T_tmm_s, O_fast_s['T']) 130 | assert torch.allclose(T_tmm_p, O_fast_p['T']) 131 | 132 | 133 | def test_coherent_stack_with_incoherent_surrounding(): 134 | n_wl = 20 135 | n_th = 45 136 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 137 | theta = torch.linspace(0, 85, n_th) * (np.pi/180) 138 | num_layers = 5 139 | num_stacks = 2 140 | mask = [[1, 2, 3]] 141 | 142 | #create m 143 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 144 | for i in range(1, M.shape[1]-1): 145 | if np.mod(i, 2) == 1: 146 | M[:, i, :] *= 1.46 147 | else: 148 | M[:, i, :] *= 2.56 149 | 150 | #create t 151 | max_t = 150 * (10**(-9)) 152 | min_t = 10 * (10**(-9)) 153 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 154 | 155 | T[:, 0] = np.inf 156 | T[:, 1] = 200e-9 157 | T[:, 2] = 100e-9 158 | T[:, 3] = 300e-9 159 | T[:, 4] = np.inf 160 | 161 | T = torch.from_numpy(T) 162 | O_fast_s = inc_tmm_fast('s', M, T, mask, theta, wl, device='cpu') 163 | O_fast_p = inc_tmm_fast('p', M, T, mask, theta, wl, device='cpu') 164 | 165 | R_tmm_s = torch.zeros((n_th, n_wl)) 166 | R_tmm_p = torch.zeros((n_th, n_wl)) 167 | T_tmm_s = torch.zeros((n_th, n_wl)) 168 | T_tmm_p = torch.zeros((n_th, n_wl)) 169 | 170 | T_list = T[0].tolist() 171 | 172 | for i, t in enumerate(theta.tolist()): 173 | for j, w in enumerate(wl.tolist()): 174 | res_s = inc_tmm('s', M[0][:, j].tolist(), T_list, ['i', 'c', 'c', 'c', 'i'], t, w) 175 | res_p = inc_tmm('p', M[0][:, j].tolist(), T_list, ['i', 'c', 'c', 'c', 'i'], t, w) 176 | R_tmm_s[i, j] = res_s['R'] 177 | R_tmm_p[i, j] = res_p['R'] 178 | T_tmm_s[i, j] = res_s['T'] 179 | T_tmm_p[i, j] = res_p['T'] 180 | 181 | if torch.cuda.is_available(): 182 | O_fast_s_gpu = inc_tmm_fast('s', M, T, mask, theta, wl, device='cuda') 183 | O_fast_p_gpu = inc_tmm_fast('p', M, T, mask, theta, wl, device='cuda') 184 | 185 | assert O_fast_s_gpu, 'gpu computation not available' 186 | assert torch.allclose(R_tmm_s, O_fast_s_gpu['R']) 187 | assert torch.allclose(R_tmm_p, O_fast_p_gpu['R']) 188 | assert torch.allclose(T_tmm_s, O_fast_s_gpu['T']) 189 | assert torch.allclose(T_tmm_p, O_fast_p_gpu['T']) 190 | 191 | assert torch.allclose(R_tmm_s, O_fast_s['R']) 192 | assert torch.allclose(R_tmm_p, O_fast_p['R']) 193 | assert torch.allclose(T_tmm_s, O_fast_s['T']) 194 | assert torch.allclose(T_tmm_p, O_fast_p['T']) 195 | assert (torch.abs(O_fast_s['R'][0]-R_tmm_s) <1e-5).all().item() 196 | assert (torch.abs(O_fast_p['R'][0]-R_tmm_p) <1e-5).all().item() 197 | assert (torch.abs(O_fast_s['T'][0]-T_tmm_s) <1e-5).all().item() 198 | assert (torch.abs(O_fast_p['T'][0]-T_tmm_p) <1e-5).all().item() 199 | 200 | def test_coherent_incoherent(): 201 | n_wl = 20 202 | n_th = 45 203 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 204 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 205 | num_layers = 5 206 | num_stacks = 2 207 | mask = [[2, 3]] 208 | 209 | #create m 210 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 211 | for i in range(1, M.shape[1]-1): 212 | if np.mod(i, 2) == 1: 213 | M[:, i, :] *= 1.46 214 | else: 215 | M[:, i, :] *= 2.56 216 | 217 | #create t 218 | max_t = 150 * (10**(-9)) 219 | min_t = 10 * (10**(-9)) 220 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 221 | 222 | T[:, 0] = np.inf 223 | T[:, 1] = 10000e-9 224 | T[:, 2] = 100e-9 225 | T[:, 3] = 300e-9 226 | T[:, -1] = np.inf 227 | 228 | T = torch.from_numpy(T) 229 | O_fast_s = inc_tmm_fast('s', M, T, mask, theta, wl, device='cpu') 230 | O_fast_p = inc_tmm_fast('p', M, T, mask, theta, wl, device='cpu') 231 | 232 | R_tmm_s = torch.zeros((n_th, n_wl)) 233 | R_tmm_p = torch.zeros((n_th, n_wl)) 234 | T_tmm_s = torch.zeros((n_th, n_wl)) 235 | T_tmm_p = torch.zeros((n_th, n_wl)) 236 | 237 | T_list = T[0].tolist() 238 | 239 | for i, t in enumerate(theta.tolist()): 240 | for j, w in enumerate(wl.tolist()): 241 | res_s = inc_tmm('s', M[0][:, j].tolist(), T_list, ['i', 'i', 'c', 'c', 'i'], t, w) 242 | res_p = inc_tmm('p', M[0][:, j].tolist(), T_list, ['i', 'i', 'c', 'c', 'i'], t, w) 243 | R_tmm_s[i, j] = res_s['R'] 244 | R_tmm_p[i, j] = res_p['R'] 245 | T_tmm_s[i, j] = res_s['T'] 246 | T_tmm_p[i, j] = res_p['T'] 247 | 248 | if torch.cuda.is_available(): 249 | O_fast_s_gpu = inc_tmm_fast('s', M, T, mask, theta, wl, device='cuda') 250 | O_fast_p_gpu = inc_tmm_fast('p', M, T, mask, theta, wl, device='cuda') 251 | 252 | assert O_fast_s_gpu, 'gpu computation not available' 253 | assert torch.allclose(R_tmm_s, O_fast_s_gpu['R']) 254 | assert torch.allclose(R_tmm_p, O_fast_p_gpu['R']) 255 | assert torch.allclose(T_tmm_s, O_fast_s_gpu['T']) 256 | assert torch.allclose(T_tmm_p, O_fast_p_gpu['T']) 257 | 258 | assert torch.allclose(R_tmm_s, O_fast_s['R']) 259 | assert torch.allclose(R_tmm_p, O_fast_p['R']) 260 | assert torch.allclose(T_tmm_s, O_fast_s['T']) 261 | assert torch.allclose(T_tmm_p, O_fast_p['T']) 262 | assert (torch.abs(O_fast_s['R'][0]-R_tmm_s) <1e-5).all().item() 263 | assert (torch.abs(O_fast_p['R'][0]-R_tmm_p) <1e-5).all().item() 264 | assert (torch.abs(O_fast_s['T'][0]-T_tmm_s) <1e-5).all().item() 265 | assert (torch.abs(O_fast_p['T'][0]-T_tmm_p) <1e-5).all().item() 266 | 267 | def test_absorbing_fully_incoherent(): 268 | n_wl = 65 269 | n_th = 45 270 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 271 | theta = torch.linspace(0, 89, n_th) * (np.pi/180) 272 | num_layers = 5 273 | num_stacks = 2 274 | mask = [] 275 | imask = ['i', 'i', 'i', 'i', 'i'] 276 | 277 | #create m 278 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 279 | for i in range(1, M.shape[1]-1): 280 | if np.mod(i, 2) == 1: 281 | M[:, i, :] *= 1.46 282 | M[:, i, :] += .005j 283 | else: 284 | M[:, i, :] *= 2.56 285 | M[:, i, :] += .002j 286 | 287 | #create t 288 | max_t = 150000 * (10**(-9)) 289 | min_t = 10000 * (10**(-9)) 290 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 291 | 292 | T[:, 0] = np.inf 293 | T[:, 1] = 10000e-9 294 | T[:, 2] = 2000e-9 295 | T[:, 3] = 5000e-9 296 | T[:, -1] = np.inf 297 | 298 | T = torch.from_numpy(T) 299 | O_fast_s = inc_tmm_fast('s', M, T, mask, theta, wl, device='cpu') 300 | O_fast_p = inc_tmm_fast('p', M, T, mask, theta, wl, device='cpu') 301 | 302 | R_tmm_s = torch.zeros((n_th, n_wl)) 303 | R_tmm_p = torch.zeros((n_th, n_wl)) 304 | T_tmm_s = torch.zeros((n_th, n_wl)) 305 | T_tmm_p = torch.zeros((n_th, n_wl)) 306 | 307 | T_list = T[0].tolist() 308 | 309 | for i, t in enumerate(theta.tolist()): 310 | for j, w in enumerate(wl.tolist()): 311 | res_s = inc_tmm('s', M[0][:, j].tolist(), T_list, imask, t, w) 312 | res_p = inc_tmm('p', M[0][:, j].tolist(), T_list, imask, t, w) 313 | R_tmm_s[i, j] = res_s['R'] 314 | R_tmm_p[i, j] = res_p['R'] 315 | T_tmm_s[i, j] = res_s['T'] 316 | T_tmm_p[i, j] = res_p['T'] 317 | 318 | if torch.cuda.is_available(): 319 | O_fast_s_gpu = inc_tmm_fast('s', M, T, mask, theta, wl, device='cuda') 320 | O_fast_p_gpu = inc_tmm_fast('p', M, T, mask, theta, wl, device='cuda') 321 | 322 | assert O_fast_s_gpu, 'gpu computation not availabla' 323 | assert torch.allclose(R_tmm_s, O_fast_s_gpu['R']) 324 | assert torch.allclose(R_tmm_p, O_fast_p_gpu['R']) 325 | assert torch.allclose(T_tmm_s, O_fast_s_gpu['T']) 326 | assert torch.allclose(T_tmm_p, O_fast_p_gpu['T']) 327 | 328 | assert torch.allclose(R_tmm_s, O_fast_s['R']) 329 | assert torch.allclose(R_tmm_p, O_fast_p['R']) 330 | assert torch.allclose(T_tmm_s, O_fast_s['T']) 331 | assert torch.allclose(T_tmm_p, O_fast_p['T']) 332 | 333 | assert (O_fast_s['R'][0].isnan() == R_tmm_s.isnan()).all() 334 | assert (O_fast_p['R'][0].isnan() == R_tmm_p.isnan()).all() 335 | assert (O_fast_s['T'][0].isnan() == T_tmm_s.isnan()).all() 336 | assert (O_fast_p['T'][0].isnan() == T_tmm_p.isnan()).all() 337 | 338 | assert (torch.abs(O_fast_s['R'][0]-R_tmm_s) <1e-5).all().item() 339 | assert (torch.abs(O_fast_p['R'][0]-R_tmm_p) <1e-5).all().item() 340 | assert (torch.abs(O_fast_s['T'][0]-T_tmm_s) <1e-5).all().item() 341 | assert (torch.abs(O_fast_p['T'][0]-T_tmm_p) <1e-5).all().item() 342 | 343 | def test_absorbing_coherent_incoherent(): 344 | n_wl = 20 345 | n_th = 45 346 | wl = torch.linspace(400, 1200, n_wl) * (10**(-9)) 347 | theta = torch.linspace(0, 85, n_th) * (np.pi/180) 348 | num_layers = 5 349 | num_stacks = 2 350 | mask = [[2, 3]] 351 | imask = ['i', 'i', 'c', 'c', 'i'] 352 | 353 | #create m 354 | M = torch.ones((num_stacks, num_layers, wl.shape[0])).type(torch.complex128) 355 | for i in range(1, M.shape[1]-1): 356 | if np.mod(i, 2) == 1: 357 | M[:, i, :] *= 1.46 358 | M[:, i, :] += .0005j 359 | else: 360 | M[:, i, :] *= 2.56 361 | M[:, i, :] += .002j 362 | 363 | #create t 364 | max_t = 150 * (10**(-9)) 365 | min_t = 10 * (10**(-9)) 366 | T = (max_t - min_t) * np.random.uniform(0, 1, (M.shape[0], M.shape[1])) + min_t 367 | 368 | T[:, 0] = np.inf 369 | T[:, 1] = 10000e-9 370 | T[:, 2] = 100e-9 371 | T[:, 3] = 300e-9 372 | T[:, -1] = np.inf 373 | 374 | T = torch.from_numpy(T) 375 | O_fast_s = inc_tmm_fast('s', M, T, mask, theta, wl, device='cpu') 376 | O_fast_p = inc_tmm_fast('p', M, T, mask, theta, wl, device='cpu') 377 | 378 | R_tmm_s = torch.zeros((n_th, n_wl)) 379 | R_tmm_p = torch.zeros((n_th, n_wl)) 380 | T_tmm_s = torch.zeros((n_th, n_wl)) 381 | T_tmm_p = torch.zeros((n_th, n_wl)) 382 | 383 | T_list = T[0].tolist() 384 | 385 | for i, t in enumerate(theta.tolist()): 386 | for j, w in enumerate(wl.tolist()): 387 | res_s = inc_tmm('s', M[0][:, j].tolist(), T_list, imask, t, w) 388 | res_p = inc_tmm('p', M[0][:, j].tolist(), T_list, imask, t, w) 389 | R_tmm_s[i, j] = res_s['R'] 390 | R_tmm_p[i, j] = res_p['R'] 391 | T_tmm_s[i, j] = res_s['T'] 392 | T_tmm_p[i, j] = res_p['T'] 393 | 394 | if torch.cuda.is_available(): 395 | O_fast_s_gpu = inc_tmm_fast('s', M, T, mask, theta, wl, device='cuda') 396 | O_fast_p_gpu = inc_tmm_fast('p', M, T, mask, theta, wl, device='cuda') 397 | 398 | assert O_fast_s_gpu, 'gpu computation not available' 399 | assert torch.allclose(R_tmm_s, O_fast_s_gpu['R']) 400 | assert torch.allclose(R_tmm_p, O_fast_p_gpu['R']) 401 | assert torch.allclose(T_tmm_s, O_fast_s_gpu['T']) 402 | assert torch.allclose(T_tmm_p, O_fast_p_gpu['T']) 403 | 404 | assert torch.allclose(R_tmm_s, O_fast_s['R']) 405 | assert torch.allclose(R_tmm_p, O_fast_p['R']) 406 | assert torch.allclose(T_tmm_s, O_fast_s['T']) 407 | assert torch.allclose(T_tmm_p, O_fast_p['T']) 408 | 409 | assert (O_fast_s['R'][0].isnan() == R_tmm_s.isnan()).all() 410 | assert (O_fast_p['R'][0].isnan() == R_tmm_p.isnan()).all() 411 | assert (O_fast_s['T'][0].isnan() == T_tmm_s.isnan()).all() 412 | assert (O_fast_p['T'][0].isnan() == T_tmm_p.isnan()).all() 413 | 414 | assert (torch.abs(O_fast_s['R'][0]-R_tmm_s) <1e-5).all().item() 415 | assert (torch.abs(O_fast_p['R'][0]-R_tmm_p) <1e-5).all().item() 416 | assert (torch.abs(O_fast_s['T'][0]-T_tmm_s) <1e-5).all().item() 417 | assert (torch.abs(O_fast_p['T'][0]-T_tmm_p) <1e-5).all().item() 418 | 419 | 420 | if __name__=='__main__': 421 | test_incoherent_input_output_medium() 422 | test_coherent_stack_with_incoherent_surrounding() 423 | test_coherent_incoherent() 424 | test_absorbing_fully_incoherent() 425 | test_absorbing_coherent_incoherent() -------------------------------------------------------------------------------- /tmm_fast/__init__.py: -------------------------------------------------------------------------------- 1 | from .vectorized_tmm_dispersive_multistack import coh_vec_tmm_disp_mstack as coh_tmm 2 | from .vectorized_incoherent_tmm import inc_vec_tmm_disp_lstack as inc_tmm 3 | 4 | 5 | from .plotting_helper import plot_stacks -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MLResearchAtOSRAM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/README.md: -------------------------------------------------------------------------------- 1 | # gym-multilayerthinfilm 2 | 3 | ## Overview 4 | The proposed OpenAI/Farama-Foundation gymnasium environment utilizes a parallelized transfer-matrix method (TMM) to implement the optimization of for multi-layer thin films as parameterized Markov decision processes. An very intuitve example is provided in example.py. 5 | Whereas the contained physical methods are well-studied and known since decades, the contribution of this code lies the transfer to an OpenAI/Farama-Foundation gymnasium environment. The intention is to enable AI researchers without optical expertise to solve the corresponding parameterized Markov decision processes. Due to their structure, the solution of such problems is still an active field of research in the AI community.
6 | The publication [Parameterized Reinforcement learning for Optical System Optimization](https://iopscience.iop.org/article/10.1088/1361-6463/abfddb) used this environment. 7 | 8 | ## Multi-layer thin films meet parameterized reinforcement learning 9 | Reinforcement learning is an area of machine learning concerned with how intelligent agents ought to take actions in an environment in order to maximize the notion of reward. The code to be published implements such an environment for the optimization of multi-layer thin films. 10 | In principle, the proposed code allows to execute actions taken by an agent. These actions determine which material of which thickness to stack next, thereby consecutively forming a multi-layer thin film as illustrated in figure 1. Such a multi-layer thin film exhibits optical characteristics. By comparison between the actual and user-defined desired characteristics, a notion of numeric reward is computed based on which the agent learns to distinguish between good and bad design choices. Due to its physical and mathematical structure, the optimization of multi-layer thin film remains a challenging and thus still active field of research in the scientific community. As such it gained recent attention in many publications. Therefore, naturally the need for a standardised environment arises to make the corresponding research more trustful, comparable and consistent. 11 | 12 | 13 | Figure 1: Principal idea of an OpenAI/Farama-Foundation gymnasium environment. The agent takes an action that specifies the material and thickness of the layer to stack next. The environment implements the multi-layer thin film generation as consecutive conduction of actions and assigns a reward to a proposed multi-layer thin film based on how close the actual (solid orange line) fulfils a desired (dashed orange line) characteristic. The made experience is used to adapt the taken actions made in order to increase the reward and thus generate more and more sophisticated multi-layer thin films. 14 | 15 | ## Describtion of key features 16 | The environment can include
17 | • cladding of the multi-layer thin film (e.g. substrate and ambient materials),
18 | • dispersive and dissipative materials,
19 | • spectral and angular optical behavior of multi-layer thin films (See figure 2),
20 | • … and many more.
21 | 22 | The environment class allows to
23 | • conduct so-called parameterized actions (See publication) that define a multi-layer thin film,
24 | • evaluate the generated thin film given a desired optical response, and
25 | • render the results (See figure 2).
26 | 27 | In general, the comprehensive optimization of multi-layer thin films in regards of optical reponse encompasses
28 | • the number of layers (integer),
29 | • the thickness of each layer (float),
30 | • the material of each layer (categrial, integer).
31 | 32 | 33 | Figure 2: Rendered output of the environment. Reflectivity (left) over angle of incidence and spectrum of a multi-layer thin film (right). Here, the stack features four layers and each layer’s material was chosen from a set of eight alternatives. The reward is computed based on a desired reflectivity, which is one for each angle and wavelength, but not displayed in this figure. 34 | 35 | 36 | ## Getting started 37 | Required packages:
38 | numpy, matplotlib, seaborn, dask, tmm as specified in env_mltf.yml 39 | based on which you can create an approbiate environment via line command
40 | conda env create -f env_mltf.yml
41 | Don't forget to specify your common python environment path (prefix, last line in env_mltf.yml)! 42 | 43 | -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | tmm - A transfer-matrix method optics package, for calculating 3 | reflection, transmission, absorption, and other relevant aspects of thin 4 | and thick multilayer (or single-layer) films. 5 | Written by Steven Byrnes, http://sjbyrnes.com . Package lives at 6 | https://pypi.python.org/pypi/tmm 7 | Released under MIT license (Expat). 8 | For details see manual.pdf (should be included with the distribution, otherwise 9 | get it at http://sjbyrnes.com/fresnel_manual.pdf ). Physics background, 10 | conventions, and derivations are at https://arxiv.org/abs/1603.02720 11 | For the various functions and their explanations and syntaxes, browse tmm_core, 12 | particularly the docstrings of all the functions. Most important of 13 | these are: 14 | tmm.coh_tmm(...) -- the transfer-matrix-method calculation in the coherent 15 | case (i.e. thin films) 16 | tmm.inc_tmm(...) -- the transfer-matrix-method calculation in the incoherent 17 | case (i.e. films tens or hundreds of wavelengths thick, or whose 18 | thickness is not very uniform. 19 | In tmm.examples you will find some sample calculations and plots. 20 | In tmm.tests you will find various tests that the package is coded 21 | correctly. 22 | In tmm.colors you will find extra functions for calculating the color of a 23 | multilayer thin film under reflected light. 24 | """ 25 | 26 | from tmm_fast.gym_multilayerthinfilm.utils import get_n_from_txt, get_N 27 | from tmm_fast.gym_multilayerthinfilm.gym_class import MultiLayerThinFilm 28 | 29 | -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/gym_class.py: -------------------------------------------------------------------------------- 1 | import random 2 | import numpy as np 3 | import gymnasium 4 | from gymnasium import spaces 5 | from ..vectorized_tmm_dispersive_multistack import coh_vec_tmm_disp_mstack as tmm 6 | import seaborn as sns 7 | import matplotlib.pyplot as plt 8 | import matplotlib 9 | 10 | class MultiLayerThinFilm(gymnasium.Env): 11 | def __init__(self, 12 | N:np.array, 13 | maximum_layers:int, 14 | target:dict, 15 | weights:np.array=None, 16 | normalization:bool=True, 17 | sparse_reward:bool=True, 18 | substrate:dict=None, 19 | ambient:dict=None, 20 | relative_reward:bool=True, 21 | max_thickness:float=150e-9, 22 | min_thickness:float=10e-9, 23 | work_path:str='')->None: 24 | """ 25 | Initialize a new environment for multi-layer thin-film (MLTF) optimization. 26 | Each layer is determined by its (dispersive) refractive index and a thickness. 27 | Thus, aside from choosing the material of a next layer to place, a reinforcement learning agent 28 | must also assign a thickness to this layer. This formulation allows to interpret the subsequent stacking of 29 | layers as a parameterized Markov decision process. (See publication for details) 30 | 31 | Contributors: Heribert Wankerl, Alexander Luce, Maike Stern 32 | (Feel free to add your name to the list in case you made major contributions or changes) 33 | Parameters: 34 | ----------- 35 | N : np.array of shape [M x S] 36 | where M is the number of available materials and S is the number of supporting points of the spectrum 37 | N holds the (dispersive, complex) refractive indices of the available materials 38 | maximum_layers : integer 39 | maximum_layers defines the maximum number of layers to stack 40 | target : dictionary 41 | with keys 'target', 'direction', 'spectrum' and 'mode' 42 | target['direction'] holds the angles [deg, °] under consideration and is of shape D 43 | target['spectrum'] holds the spectrum [m] under consideration and is of shape S 44 | target['target'] holds the pixel-wise target reflectivity of a MLTF and is of shape [D x S] 45 | target['mode'] states whether to use reflectivity' or 'transmittivity' 46 | weights : np.array of same shape [D x S] 47 | This array allows to steer the pixels relative influence on the optimization/reward 48 | normalization : bool 49 | Determines whether to exponentially transform the reward or not (Look publication for details) 50 | sparse_reward : bool 51 | Determines whether to simulate and reward each intermediate stack or only the final stack 52 | substrate : dictionary or None 53 | Holds the (dispersive, complex) refractive indices of the substrate materials in the rows of 54 | substrate['n'] which is of shape np.array of shape [Sub x S] . Sub is the number of materials that form 55 | the substrate. substrate['d'] is of shape Sub and holds the corresponding thicknesses of each layer. 56 | If substrate is None (default) it is set to vacuum of infinite thickness. 57 | ambient : dictionary or None 58 | Holds the (dispersive, complex) refractive indices of the ambient materials in the rows of 59 | ambient['n'] which is of shape np.array of shape [Am x S] . Am is the number of materials that form 60 | the ambient. ambient['d'] is of shape Am and holds the corresponding thicknesses of each layer. 61 | If ambient is None (default) it is set to vacuum of infinite thickness. 62 | relative_reward : bool 63 | Impact only if sparse_reward is False. Determines whether the provided reward signal for a stack is 64 | computed independently (False) or as difference between two subsequent rewards (True), i.e. improvements 65 | achieved by an action are measured by the reward in the latter case. 66 | max_thickness : float 67 | Determines the maximum layer thickness in meter. 68 | min_thickness : float 69 | Determines the minimum layer thickness in meter. 70 | work_path : str 71 | Path to working directory e.g. to save images 72 | """ 73 | 74 | self.N = N 75 | self.maximum_layers = maximum_layers 76 | # target-related: 77 | # wavelength range 78 | self.wl = target['spectrum'] 79 | # mode: 'reflectivity' or 'transmittivity' 80 | if target['mode'] == 'transmittivity' or target['mode'] == 'reflectivity': 81 | self.mode = target['mode'] 82 | else: 83 | self.mode = 'reflectivity' 84 | print('Invalid mode -> set to reflectivity!') 85 | # angel range 86 | self.angle = target['direction'] 87 | # desired value for reflectivity (pixelwise) 88 | self.target = target['target'] 89 | if weights is None: 90 | self.weights = np.ones_like(self.target) 91 | # reward computation: 92 | self.normalization = normalization 93 | self.sparse_reward = sparse_reward 94 | # cladding: 95 | if substrate is not None: 96 | self.n_substrate = substrate['n'] 97 | self.d_substrate = substrate['d'] 98 | else: 99 | self.n_substrate = np.ones((1, self.wl.shape[0])) 100 | self.d_substrate = np.array([np.inf]) 101 | print('--- substrate is set to vacuum of infinite thickness ---') 102 | if ambient is not None: 103 | self.n_ambient = ambient['n'] 104 | self.d_ambient = ambient['d'] 105 | else: 106 | self.n_ambient = np.ones((1, self.wl.shape[0])) 107 | self.d_ambient = np.array([np.inf]) 108 | print('--- ambient is set to vacuum of infinite thickness ---') 109 | if np.iscomplex(self.n_substrate[0, :]).any(): 110 | self.n_substrate[0, :] = np.real(self.n_substrate[0, :]) 111 | print('n_substrate must feature real-valued refractive indicies in first layer for computational/physical reasons (TMM); adopted via np.real()') 112 | if np.iscomplex(self.n_ambient[-1, :]).any(): 113 | self.n_ambient[-1, :] = np.real(self.n_ambient[-1, :]) 114 | print('n_ambient must feature real-valued refractive indicies in last layer for computational/physical reasons (TMM); adopted via np.real()') 115 | assert not np.iscomplex(self.n_substrate[0, :]).any(), 'n_substrate must feature real-valued refractive indicies in first layer for computational/physical reasons (TMM)..' 116 | assert not np.iscomplex(self.n_ambient[-1, :]).any(), 'n_ambient must feature real-valued refractive indicies in last layer for computational/physical reasons (TMM)..' 117 | self.d_substrate = self.d_substrate.reshape(-1, 1) 118 | self.d_ambient = self.d_ambient.reshape(-1, 1) 119 | 120 | self.work_path = work_path 121 | # borders for thicknesses: 122 | self.max_thickness = max_thickness 123 | self.min_thickness = min_thickness 124 | 125 | # initialization for some attributes: 126 | self.number_of_materials = N.shape[0] 127 | self.simulation = np.nan * np.zeros_like(self.target) 128 | self.reward = None 129 | self.old_reward = None 130 | self.relative_reward = relative_reward 131 | self._reward_track = [] 132 | self.layers = [] 133 | self._initial_nmb_layers = 0 134 | 135 | self.n = [] 136 | self.d = [] 137 | self.f = None 138 | self.axs = None 139 | # OpenAI/Farama-Foundation gymnasium related settings: 140 | # action space: 141 | space_list = [spaces.Discrete((self.number_of_materials + 1))] 142 | for space in range(self.number_of_materials + 1): 143 | space_list.append(spaces.Box(low=0, high=1, shape=(1,))) 144 | self.action_space = spaces.Tuple(space_list) 145 | 146 | # simulation state space: 147 | self.observation_space = spaces.Box(low=0, high=1, shape=((self.number_of_materials + 1)*maximum_layers, ), dtype=np.float64) 148 | if weights is None: 149 | self.weights = np.ones_like(self.target) 150 | else: 151 | self.weights = weights 152 | assert weights.shape[0] == self.target.shape[0] and weights.shape[1] == self.target.shape[1], 'Shape of weights and target must coincide!' 153 | assert np.all(weights >= 0), 'weights are supposed to be non-negative!' 154 | if np.all(weights == 0): 155 | self.weights = np.ones_like(self.target) 156 | print('All weights were zero -> if nothing is important quit optimization; we set each weight to one for you ;)...') 157 | self.weights = self.weights / np.max(self.weights) 158 | assert self.N.shape == tuple([self.number_of_materials, self.wl.shape[0]]), 'N does not match with target!' 159 | 160 | def set_cladding(self, substrate=None, ambient=None): 161 | if substrate is not None: 162 | self.n_substrate = substrate['n'] 163 | self.d_substrate = substrate['d'] 164 | else: 165 | self.n_substrate = np.ones((1, self.wl.shape[0])) 166 | self.d_substrate = np.array([np.inf]).squeeze() 167 | if ambient is not None: 168 | self.n_ambient = ambient['n'] 169 | self.d_ambient = ambient['d'] 170 | else: 171 | self.n_ambient = np.ones((1, self.wl.shape[0])) 172 | self.d_ambient = np.array([np.inf]).squeeze() 173 | print('--- ambient is set to vacuum of infinite thickness ---') 174 | if np.iscomplex(self.n_substrate[0, :]).any(): 175 | self.n_substrate[0, :] = np.real(self.n_substrate[0, :]) 176 | print( 177 | 'n_substrate must feature real-valued refractive indicies in first layer for computational/physical reasons (TMM); adopted via np.real()') 178 | if np.iscomplex(self.n_ambient[-1, :]).any(): 179 | self.n_ambient[-1, :] = np.real(self.n_ambient[-1, :]) 180 | print( 181 | 'n_ambient must feature real-valued refractive indicies in last layer for computational/physical reasons (TMM); adopted via np.real()') 182 | assert not np.iscomplex(self.n_substrate[0, :]).any(), 'n_substrate must feature real-valued refractive indicies in first layer for computational/physical reasons (TMM)..' 183 | assert not np.iscomplex(self.n_ambient[-1, :]).any(), 'n_ambient must feature real-valued refractive indicies in last layer for computational/physical reasons (TMM)..' 184 | self.d_substrate = self.d_substrate.reshape(-1, 1) 185 | self.d_ambient = self.d_ambient.reshape(-1, 1) 186 | print('cladding set....') 187 | 188 | def step(self, action): 189 | """ 190 | This method implements the conduction of an action in the environment. Namely, to stack a layer of a 191 | particular thickness on top of an existing stack. 192 | 193 |         Args: 194 | 195 |           action: np.array of shape [2] 196 | action[0] holds the material chosen by the agent as an integer value. Note that 0 leads to 197 | termination of stacking. action[1] is a float between 0 and 1 and encodes the assigned thickness. 198 | 199 | Rets: 200 | self.simulation: np.array of shape [D x S] 201 | holds the reflectivity for each direction and wavelength of a particular stack in its entries. 202 | self.n: list 203 | List of np.arrays of shape [1 x S] that holds the refractive indicies of the stacked layers 204 | self.d: list 205 | List of floats that determine the thicknesses of each stacked layer. 206 | one_hot_status: np.array of shape [Maximum number of layers L times number of available materials M] 207 | Each M-th partition (of L partitions) one-hot encodes a normalized layer thickness and the layer material. In total, this vector encodes the entire stack. 208 | handback_reward: float 209 | rates the current stack based on its fullfillment of the target characteristics; can be relative or absolute 210 | done: Boolean 211 | done-flag that determines whether to end stacking or not. 212 | []: Empty list 213 | No info list available 214 |         """ 215 | 216 | done = False 217 | self.old_reward = self.reward 218 | if action[0] == 0 or len(self.layers) >= self.maximum_layers: 219 | done = True 220 | else: 221 | self.layers.append(int(action[0])) 222 | n_layer = self.N[int(action[0] - 1), :].reshape(1, -1) 223 | d_layer = (self.max_thickness - self.min_thickness) * action[1] + self.min_thickness 224 | self.n.append(n_layer) 225 | self.d.append(d_layer) 226 | cladded_n, cladded_d = self.stack_layers() 227 | self.simulation = self.simulate(cladded_n, cladded_d) 228 | self.reward = 0 229 | if done or not self.sparse_reward: 230 | self.reward, mse = self.reward_func(self.simulation, self.target, self.weights, self.baseline_mse, self.normalization) 231 | if done: 232 | self._reward_track.append(mse) # track reward to compute baseline 233 | if np.all(np.isnan(self.simulation)): 234 | print('All simulated values in TMM are NaN!') 235 | one_hot_status = self.one_hot_layer_status() 236 | if self.relative_reward and not self.sparse_reward and self.old_reward is not None and self.reward is not None: 237 | relative_reward = self.reward - self.old_reward 238 | handback_reward = relative_reward 239 | else: 240 | handback_reward = self.reward 241 | return [self.simulation, self.n, self.d, one_hot_status], handback_reward, done, [] 242 | 243 | def one_hot_layer_status(self): 244 | one_hot_vectors = [] 245 | for layer in range(self.maximum_layers): 246 | one_hot_vector = np.zeros((self.number_of_materials + 1)) 247 | if layer < len(self.layers): 248 | one_hot_vector[int(self.layers[layer])] = 1* self.normalize_thickness(self.d[layer]) 249 | one_hot_vectors.append(one_hot_vector) 250 | one_hot_vectors = np.hstack(one_hot_vectors) 251 | return one_hot_vectors 252 | 253 | def denormalize_thickness(self, t): 254 | t = (self.max_thickness - self.min_thickness) * t + self.min_thickness 255 | return t 256 | 257 | def normalize_thickness(self, t): 258 | t = (t - self.min_thickness) / (self.max_thickness - self.min_thickness) 259 | return t 260 | 261 | def reset(self): 262 | """ 263 | This method implements the reset of the environment to a initial state. However, to ease exploration, 264 | a defined number of layers can be stacked before handing it to the agent. 265 | 266 |         Args: 267 | 268 |           self 269 | 270 | Rets: 271 | All of this returns are computed based on the initial stack determined by the user 272 | self.simulation: np.array of shape [D x S] 273 | holds the reflectivity for each direction and wavelength of a particular stack in its entries. 274 | self.reward: float 275 | rates the current stack based on its fullfillment of the target characteristics 276 | self.n: list 277 | List of np.arrays of shape [1 x S] that holds the refractive indicies of the stacked layers 278 | self.d: list 279 | List of floats that determine the thicknesses of each stacked layer. 280 |         """ 281 | self.layers = [] 282 | self.n = [] 283 | self.d = [] 284 | if self._initial_nmb_layers > 0: 285 | num_layers = random.randint(1, self._initial_nmb_layers - 1) 286 | for _ in range(num_layers): 287 | rnd_material_idx = random.randint(0, self.number_of_materials-1) 288 | rnd_material_d = random.uniform(0, 1) 289 | self.layers.append(rnd_material_idx+1) 290 | n_layer = self.N[rnd_material_idx].reshape(1, -1) 291 | d_layer = (self.max_thickness - self.min_thickness) * rnd_material_d + self.min_thickness 292 | self.n.append(n_layer) 293 | self.d.append(d_layer) 294 | cladded_n, cladded_d = self.stack_layers() 295 | self.simulation = self.simulate(cladded_n, cladded_d) 296 | 297 | self.reward = 0 298 | if not self.sparse_reward: 299 | self.reward, _ = self.reward_func(self.simulation, self.target, self.weights, self.baseline_mse, self.normalization) 300 | one_hot_status = self.one_hot_layer_status() 301 | return [self.simulation, self.n, self.d, one_hot_status], self.reward, [], [] 302 | 303 | def render(self, conduct_simulation=True, scale=False): 304 | """ 305 | This method renders the current multi-layer thin film and associated optical response 306 |         Args: 307 | 308 |           conduct_simulation: Boolean 309 | states whether to conduct the simulation or use the currently stored 310 | 311 | Rets: 312 | Figure related objects to e.g. envolve them further 313 | self.f: Figure 314 | self.axs: ndarray of shape (2) holding AxesSubplots 315 | 316 |         """ 317 | colors = list(matplotlib.colors.TABLEAU_COLORS.keys()) 318 | cbar = True 319 | if self.f is None: 320 | self.f, self.axs = plt.subplots(nrows=1, ncols=3, ) 321 | else: 322 | if plt.fignum_exists(self.f.number): 323 | self.axs[0].clear() 324 | self.axs[1].clear() 325 | self.axs[2].clear() 326 | cbar = False 327 | else: 328 | self.f, self.axs = plt.subplots(nrows=1, ncols=3, ) 329 | assert self.N.shape[0] <= len(colors), 'Not enough colors to illustrate all materials in N!' 330 | # plot reflectivity: 331 | if conduct_simulation: 332 | cladded_n, cladded_d = self.stack_layers() 333 | self.simulation = self.simulate(cladded_n, cladded_d) 334 | self.reward, _ = self.reward_func(self.simulation, self.target, self.weights, self.baseline_mse, self.normalization) 335 | if scale: 336 | min_val = np.min(self.simulation) 337 | max_val = np.max(self.simulation) 338 | else: 339 | min_val = 0 340 | max_val = 1 341 | # drawing: 342 | assert self.wl.shape[0] > 1 or self.angle.shape[0] > 1, 'No rendering for single wavelenght and single direction!' 343 | if self.angle.shape[0] == 1: 344 | xaxis = np.linspace(0, self.wl.shape[0], 10, dtype=int) 345 | xtickslabels = np.linspace(np.min(self.wl * 10 ** 9), np.max(self.wl * 10 ** 9), 10, dtype=int) 346 | plt.sca(self.axs[0]) 347 | plt.plot(self.simulation.squeeze()) 348 | plt.xticks(xaxis, xtickslabels) 349 | plt.xlabel('Wavelength [nm]') 350 | plt.ylabel('Reflectivity [1]') 351 | plt.ylim([0, 1.05]) 352 | plt.title('Reflectivity at incidence angle of ' + str(self.angle[0]) + '°\nReward = ' + str(np.round(self.reward, 4))) 353 | elif self.wl.shape[0] == 1: 354 | xaxis = np.linspace(0, self.angle.shape[0], 10, dtype=int) 355 | xtickslabels = np.linspace(np.min(self.angle), np.max(self.angle), 10, dtype=int) 356 | plt.sca(self.axs[0]) 357 | plt.plot(self.simulation.squeeze()) 358 | plt.xticks(xaxis, xtickslabels) 359 | plt.xlabel('Angle [deg, °]') 360 | plt.ylabel('Reflectivity [1]') 361 | plt.ylim([0, 1.05]) 362 | plt.title('Reflectivity at wavelength ' + str(np.round(self.wl[0] * 10 ** 9, 3)) + ' nm\nReward = ' + str(np.round(self.reward, 4))) 363 | else: 364 | yticks = np.linspace(0, self.target.shape[0], 10, dtype=int) 365 | ytickslabels = np.linspace(np.min(self.angle), np.max(self.angle), 10, dtype=int) 366 | xticks = np.linspace(0, self.target.shape[1], 10, dtype=int) 367 | xtickslabels = np.linspace(np.min(self.wl*10**9), np.max(self.wl*10**9), 10, dtype=int) 368 | colormap = None # 'twilight' 369 | g = sns.heatmap(self.simulation, vmin=min_val, vmax=max_val, ax=self.axs[0], xticklabels=xtickslabels, yticklabels=ytickslabels, 370 | cmap=colormap, cbar=cbar) 371 | g.set_xticks(xticks) 372 | g.set_yticks(yticks) 373 | g.set_ylabel('Angle [deg, °]') 374 | g.set_xlabel('Wavelength [nm]') 375 | g.set_xticklabels(g.get_xticklabels(), rotation=45) 376 | g.set_yticklabels(g.get_yticklabels(), rotation=0) 377 | g.set_title('Reflectivity\nReward = ' + str(np.round(self.reward, 4))) 378 | 379 | # plot stack: 380 | plt.sca(self.axs[1]) 381 | self.axs[1].yaxis.tick_right() 382 | self.axs[1].yaxis.set_label_position("right") 383 | self.axs[1].yaxis.grid(linestyle='dotted') 384 | # for major ticks 385 | self.axs[1].set_xticks([]) 386 | # for minor ticks 387 | self.axs[1].set_xticks([], minor=True) 388 | self.axs[1].ticklabel_format(axis='y', style='sci', scilimits=(-9, -9), useOffset=None, useLocale=None, useMathText=None) 389 | ind = np.array([1]) 390 | width = 0.25 391 | for layer, nidx in enumerate(self.layers): 392 | plt.bar(ind[0], self.d[layer], width, bottom=np.sum(self.d[:layer]), color=colors[int(nidx)-1]) 393 | num_materials = self.num_layers 394 | plt.xticks(ind, 395 | ('Multi-layer thin film\n' + str(num_materials) + ' layers',)) 396 | plt.ylabel('Thickness [m]') 397 | 398 | # # # MATERIAL LEGEND: 399 | plt.sca(self.axs[2]) 400 | plt.axis('off') 401 | from matplotlib.lines import Line2D 402 | legend_elements = [Line2D([0], [0], color=colors[idx], lw=10, label='Material ' + str(idx+1)) for idx in range(self.N.shape[0])] 403 | plt.legend(handles=legend_elements, loc='center right') 404 | plt.tight_layout() 405 | plt.show(block=False) 406 | plt.pause(0.1) 407 | return [self.f, self.axs] 408 | 409 | def render_target(self): 410 | assert self.wl.shape[0] > 1 or self.angle.shape[0] > 1, 'No rendering for single wavelenght and single direction!' 411 | f_target, axs_target = plt.subplots(nrows=1, ncols=2, ) 412 | # plot target: 413 | if self.angle.shape[0] == 1: 414 | xaxis = np.linspace(0, self.wl.shape[0], 10, dtype=int) 415 | xtickslabels = np.linspace(np.min(self.wl * 10 ** 9), np.max(self.wl * 10 ** 9), 10, dtype=int) 416 | #target: 417 | plt.sca(axs_target[0]) 418 | plt.plot(self.target.squeeze()) 419 | plt.xticks(xaxis, xtickslabels) 420 | plt.xlabel('Wavelength [nm]') 421 | plt.ylabel(self.mode + ' [1]') 422 | plt.ylim([0, 1.05]) 423 | plt.title('Target at incidence angle of ' + str(self.angle[0]) + ' °') 424 | #weights 425 | plt.sca(axs_target[1]) 426 | plt.plot(self.weights.squeeze()) 427 | plt.xticks(xaxis, xtickslabels) 428 | plt.xlabel('Wavelength [nm]') 429 | plt.ylabel('Weight [1]') 430 | plt.ylim([0, 1.05 * np.max(self.weights)]) 431 | plt.title('Weights at incidence angle of ' + str(self.angle[0]) + ' °') 432 | elif self.wl.shape[0] == 1: 433 | xaxis = np.linspace(0, self.angle.shape[0], 10, dtype=int) 434 | xtickslabels = np.linspace(np.min(self.angle), np.max(self.angle), 10, dtype=int) 435 | #target 436 | plt.sca(axs_target[0]) 437 | plt.plot(self.target.squeeze()) 438 | plt.xticks(xaxis, xtickslabels) 439 | plt.xlabel('Angle [deg, °]') 440 | plt.ylabel(self.mode + ' [1]') 441 | plt.ylim([0, 1.05]) 442 | plt.title('Target at wavelength ' + str(np.round(self.wl[0] * 10 ** 9, 3)) + ' nm') 443 | # weights 444 | plt.sca(axs_target[1]) 445 | plt.plot(self.weights.squeeze()) 446 | plt.xticks(xaxis, xtickslabels) 447 | plt.xlabel('Angle [deg, °]') 448 | plt.ylabel('Weight [1]') 449 | plt.ylim([0, 1.05 * np.max(self.weights)]) 450 | plt.title('Weights at wavelength ' + str(np.round(self.wl[0] * 10 ** 9, 3)) + ' nm') 451 | else: 452 | yticks = np.linspace(0, self.target.shape[0], 10, dtype=int) 453 | ytickslabels = np.linspace(np.min(self.angle), np.max(self.angle), 10, dtype=int) 454 | xticks = np.linspace(0, self.target.shape[1], 10, dtype=int) 455 | xtickslabels = np.linspace(np.min(self.wl * 10 ** 9), np.max(self.wl * 10 ** 9), 10, dtype=int) 456 | colormap = None # 'twilight' 457 | # target: 458 | g = sns.heatmap(self.target, vmin=0, vmax=1, ax=axs_target[0], xticklabels=xtickslabels, yticklabels=ytickslabels, cmap=colormap) 459 | g.set_xticks(xticks) 460 | g.set_yticks(yticks) 461 | g.set_ylabel('Angle [deg, °]') 462 | g.set_xlabel('Wavelength [nm]') 463 | g.set_xticklabels(g.get_xticklabels(), rotation=45) 464 | g.set_yticklabels(g.get_yticklabels(), rotation=0) 465 | g.set_title('Target over angle and spectrum') 466 | # weights: 467 | g = sns.heatmap(self.weights, vmin=0, ax=axs_target[1], xticklabels=xtickslabels, yticklabels=ytickslabels, cmap=colormap) 468 | g.set_xticks(xticks) 469 | g.set_yticks(yticks) 470 | g.set_ylabel('Angle [deg, °]') 471 | g.set_xlabel('Wavelength [nm]') 472 | g.set_xticklabels(g.get_xticklabels(), rotation=45) 473 | g.set_yticklabels(g.get_yticklabels(), rotation=0) 474 | g.set_title('Weights over angle and spectrum') 475 | plt.tight_layout() 476 | plt.show(block=False) 477 | plt.pause(0.1) 478 | return [f_target, axs_target] 479 | 480 | def simulate(self, n, d): 481 | """ 482 | This method implements the simulation of the reflectivity of a particular stack. The TMM and its 483 | parallelization is based on previous work of Alexander Luce. 484 | 485 |         Args: 486 | 487 |          n: np.array of shape [(Sub + L + Am) x S] 488 | n holds the refractive indicies of L stacked layers by the agent, including substrate and ambient. 489 | d: np.array of shape Sub + L + Am 490 | d holds the thicknesses in meter of the layers 491 | 492 | Rets: 493 | 494 | r: np.array of shape [D x S] 495 | r holds the pixel-wise reflectivity values for the directions and wavelengths under consideration 496 |         """ 497 | result_dicts = tmm('s', n, d, (np.pi/180)*self.angle, self.wl) 498 | result_dictp = tmm('p', n, d, (np.pi/180)*self.angle, self.wl) 499 | if self.mode == 'reflectivity': 500 | rs = result_dicts['R'] 501 | rp = result_dictp['R'] 502 | r = (rs + rp) / 2 503 | return r 504 | else: 505 | ts = result_dicts['T'] 506 | tp = result_dictp['T'] 507 | t = (ts + tp) / 2 508 | return t 509 | 510 | def create_action(self, mat_number, thickness, is_normalized=True): 511 | if not is_normalized: 512 | normalized_thickness = (thickness - self.min_thickness) / (self.max_thickness - self.min_thickness) 513 | else: 514 | normalized_thickness = thickness 515 | action = tuple((mat_number, np.array([normalized_thickness]))) 516 | return action 517 | 518 | def create_stack(self, material_list, thickness_list=None): 519 | if thickness_list is not None: 520 | t = np.stack((thickness_list)) 521 | else: 522 | t = np.empty() 523 | n = [] 524 | for material in material_list: 525 | n.append(self.N[material-1, :]) 526 | n = np.vstack((n)) 527 | dictionary = {'n': n, 'd': t} 528 | return n, t, dictionary 529 | 530 | def stack_layers(self, d_array=None, n_array=None): 531 | """ 532 | This method clads the stack suggested by the agent with the pre-defined cladding. 533 | The returned arrays n, d describe a particular stack, it includes the cladding. 534 |         """ 535 | 536 | if n_array is not None: 537 | n_list = list(n_array) 538 | else: 539 | n_list = self.n 540 | if d_array is not None: 541 | d_list = list(d_array) 542 | else: 543 | d_list = self.d 544 | 545 | if len(n_list) != 0: 546 | cladded_n = np.vstack((n_list)) 547 | cladded_d = np.vstack((d_list)).reshape(-1, 1) 548 | cladded_n = np.vstack((self.n_substrate, cladded_n)) 549 | cladded_d = np.vstack((self.d_substrate, cladded_d)) 550 | cladded_n = np.vstack((cladded_n, self.n_ambient)) 551 | cladded_d = np.vstack((cladded_d, self.d_ambient)) 552 | else: 553 | cladded_n = np.vstack((self.n_substrate, self.n_ambient)) 554 | cladded_d = np.vstack((self.d_substrate, self.d_ambient)) 555 | return cladded_n.squeeze(), cladded_d.squeeze() 556 | 557 | def steps_made(self): 558 | """ 559 | Returns the number of steps made in the environment 560 |         """ 561 | return len(self.layers) 562 | 563 | def reset_reward_track(self): 564 | """ 565 | To reset private property _reward_track. 566 |         """ 567 | self._reward_track = [] 568 | 569 | def set_initial_layers(self, nmb_of_initial_layers): 570 | """ 571 | Setter for the private property that specifies an initial number of layers during environment reset 572 |         """ 573 | if nmb_of_initial_layers > self.maximum_layers: 574 | raise ValueError("Initial number of layers already exceeds total number of allowed layers!") 575 | self._initial_nmb_layers = nmb_of_initial_layers 576 | 577 | @property 578 | def baseline_mse(self): 579 | """ 580 | Returns the baseline mse for reward computation/transformation (See publication for details) 581 |         """ 582 | if len(self._reward_track) == 0: 583 | return 0.4 584 | else: 585 | return 0.4 # np.mean(self._reward_track) 586 | 587 | @property 588 | def num_layers(self)->float: 589 | """ 590 | Returns the explicit number of layers of a stack 591 | """ 592 | if len(self.layers) == 0: 593 | return 0 594 | else: 595 | counter = 0 596 | prev_layer = -1 597 | for layer in self.layers: 598 | if not layer == prev_layer: 599 | counter += 1 600 | prev_layer = layer 601 | return counter 602 | 603 | @staticmethod 604 | def reward_func(reflectivity, target, weights=None, baseline_mse=1.0, normalization=False, low_reward=0.01, high_reward=1.0): 605 | """ 606 | An unconstrained reward computation based on the observed reflectivity and the given target. 607 | """ 608 | if weights is None: 609 | weights = np.ones_like(target) 610 | else: 611 | assert np.all(weights >= 0), 'weights are supposed to be non-negative!' 612 | temp = np.abs(reflectivity - target) * weights 613 | temp[weights == 0] = np.nan 614 | baseline_error = np.nanmean(temp) 615 | if normalization: 616 | assert low_reward > 0, 'low_rewards needs to be non-negative!' 617 | highest_measureable_reward = high_reward 618 | lowest_measureable_reward = low_reward # > 0 619 | a = highest_measureable_reward 620 | b = np.log(lowest_measureable_reward / highest_measureable_reward) / baseline_mse 621 | reward = a * np.exp(b * baseline_error) 622 | else: 623 | reward = np.exp(-baseline_error) 624 | return reward, baseline_error 625 | -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/gym_environment_example.py: -------------------------------------------------------------------------------- 1 | import gym_multilayerthinfilm as mltf 2 | import numpy as np 3 | 4 | # Material specifications 5 | # Pathes were material txt-files are stored are gathered in a list 6 | pathAu = 'materials\\nAu.txt' 7 | pathNb2O5 = 'materials\\nNb2O5.txt' 8 | pathSiO2 = 'materials\\nSiO2.txt' 9 | 10 | material_path_list = [pathAu, pathNb2O5, pathSiO2] 11 | 12 | # Specification of operation mode as well as angular and spectral range of interest 13 | 14 | mode = 'reflectivity' # 'transmittivity' or 'reflectivity' 15 | maximum_number_of_layers = 10 16 | angle_min = 0 # ° 17 | angle_max = 90 # ° 18 | lambda_min = 400 # nm 19 | lambda_max = 700 # nm 20 | 21 | # Definition of the target reflectivity for each angle and wavelength (pixelwise as an array) 22 | target_array = 0.5 * np.ones((int(angle_max - angle_min), int(lambda_max - lambda_min))) 23 | 24 | 25 | wl = np.linspace(lambda_min, lambda_max, int(lambda_max - lambda_min)) * 1e-9 26 | angle = np.linspace(angle_min, angle_max, int(angle_max - angle_min)) 27 | target = {'direction': angle, 'spectrum': wl, 'target': target_array, 'mode': mode} 28 | 29 | N = mltf.get_N(material_path_list, lambda_min, lambda_max, points=int(lambda_max - lambda_min), complex_n=True) 30 | N = np.vstack((N, np.ones((1, N.shape[1])))) 31 | 32 | # Creation of the environment given the above information 33 | env = mltf.MultiLayerThinFilm(N, maximum_number_of_layers, target) 34 | 35 | env.reset() 36 | 37 | # By default the multilayer thin film is cladded by vacuum of infinite thickness. 38 | # Well, let's assume that the light injection layer is actually air (which is very close to vacuum), 39 | # but the ambient consists of gold (Au) of infinite thickness. In case that the ambient consisits of more stacked 40 | # materials, we can just expand the list properly! 41 | # The procedure remains the same for the substrate of course. 42 | 43 | #ambient: 44 | ambient_material_list = [2] 45 | ambient_thickness_list = [np.inf] 46 | # The create_stack-method forms a dictionary that defines the ambient: 47 | _, _, ambient_dict = env.create_stack(ambient_material_list, ambient_thickness_list) 48 | env.set_cladding(ambient=ambient_dict) 49 | # We might get warned, if the refractive indexes in the ambient are non-real! 50 | 51 | 52 | # In the following, a particular multilayer thin film is constructed inbetween the aforementioned cladding 53 | # via consecutive layer stacking. Here, the thin film consists of tow layers (Nb2O5 and SiO2) of thicknesses 10 nm each: 54 | layer_material_list = [2, 3] 55 | for layer in layer_material_list: 56 | # Execute steps to form multilayer thin film via layer stacking: 57 | env.step(env.create_action(layer, thickness=10e-9)) 58 | # And another three random layers: 59 | env.step(env.action_space.sample()) 60 | env.step(env.action_space.sample()) 61 | # For the last step, we read out the state-list as well as the reward and done-flag. 62 | # Note that the read-out reward is only non-zero if done==True in case that env.sparse_reward is True, therefore we set: 63 | env.sparse_reward = False 64 | [simulation, n, d], reward, done, _ = env.step(env.action_space.sample()) 65 | 66 | # Finally, we render the target that was provided above as well as the current state of the environment 67 | # Namely, the state is defined by the currently formed thin film as well as the corresponding optical behavior 68 | env.render_target() 69 | env.render() 70 | print(':)') 71 | -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/gym_multilayerthinfilm.yml: -------------------------------------------------------------------------------- 1 | name: mltf 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - blas=1.0=mkl 7 | - bokeh=2.3.3=py39haa95532_0 8 | - bottleneck=1.3.2=py39h7cc1a96_1 9 | - ca-certificates=2021.7.5=haa95532_1 10 | - certifi=2021.5.30=py39haa95532_0 11 | - click=8.0.1=pyhd3eb1b0_0 12 | - cloudpickle=1.6.0=py_0 13 | - colorama=0.4.4=pyhd3eb1b0_0 14 | - cycler=0.10.0=py39haa95532_0 15 | - cytoolz=0.11.0=py39h2bbff1b_0 16 | - dask=2021.7.0=pyhd3eb1b0_0 17 | - dask-core=2021.7.0=pyhd3eb1b0_0 18 | - distributed=2021.7.0=py39haa95532_0 19 | - ffmpeg=4.3.1=ha925a31_0 20 | - freetype=2.10.4=hd328e21_0 21 | - fsspec=2021.7.0=pyhd3eb1b0_0 22 | - future=0.18.2=py39hcbf5309_3 23 | - gym=0.18.0=py39h832f523_1 24 | - heapdict=1.0.1=py_0 25 | - icc_rt=2019.0.0=h0cc432a_1 26 | - icu=58.2=ha925a31_3 27 | - importlib-metadata=3.10.0=py39haa95532_0 28 | - intel-openmp=2021.3.0=haa95532_3372 29 | - jinja2=3.0.1=pyhd3eb1b0_0 30 | - jpeg=9b=hb83a4c4_2 31 | - kiwisolver=1.3.1=py39hd77b12b_0 32 | - libpng=1.6.37=h2a8f88b_0 33 | - libtiff=4.2.0=hd0e1b90_0 34 | - locket=0.2.1=py39haa95532_1 35 | - lz4-c=1.9.3=h2bbff1b_0 36 | - markupsafe=2.0.1=py39h2bbff1b_0 37 | - matplotlib=3.3.4=py39haa95532_0 38 | - matplotlib-base=3.3.4=py39h49ac443_0 39 | - mkl=2021.3.0=haa95532_524 40 | - mkl-service=2.4.0=py39h2bbff1b_0 41 | - mkl_fft=1.3.0=py39h277e83a_2 42 | - mkl_random=1.2.2=py39hf11a4ad_0 43 | - msgpack-python=1.0.2=py39h59b6b97_1 44 | - numexpr=2.7.3=py39hb80d3ca_1 45 | - numpy=1.20.3=py39ha4e8547_0 46 | - numpy-base=1.20.3=py39hc2deb75_0 47 | - olefile=0.46=py_0 48 | - openssl=1.1.1k=h2bbff1b_0 49 | - packaging=21.0=pyhd3eb1b0_0 50 | - pandas=1.3.0=py39hd77b12b_0 51 | - partd=1.2.0=pyhd3eb1b0_0 52 | - pillow=8.3.1=py39h4fa10fc_0 53 | - pip=21.1.3=py39haa95532_0 54 | - psutil=5.8.0=py39h2bbff1b_1 55 | - pyglet=1.5.16=py39hcbf5309_0 56 | - pyparsing=2.4.7=pyhd3eb1b0_0 57 | - pyqt=5.9.2=py39hd77b12b_6 58 | - python=3.9.5=h6244533_3 59 | - python-dateutil=2.8.2=pyhd3eb1b0_0 60 | - python_abi=3.9=2_cp39 61 | - pytz=2021.1=pyhd3eb1b0_0 62 | - pyyaml=5.4.1=py39h2bbff1b_1 63 | - qt=5.9.7=vc14h73c81de_0 64 | - scipy=1.6.2=py39h66253e8_1 65 | - seaborn=0.11.1=pyhd3eb1b0_0 66 | - setuptools=52.0.0=py39haa95532_0 67 | - sip=4.19.13=py39hd77b12b_0 68 | - six=1.16.0=pyhd3eb1b0_0 69 | - sortedcontainers=2.4.0=pyhd3eb1b0_0 70 | - sqlite=3.36.0=h2bbff1b_0 71 | - tblib=1.7.0=py_0 72 | - tk=8.6.10=he774522_0 73 | - toolz=0.11.1=pyhd3eb1b0_0 74 | - tornado=6.1=py39h2bbff1b_0 75 | - typing_extensions=3.10.0.0=pyh06a4308_0 76 | - tzdata=2021a=h52ac0ba_0 77 | - vc=14.2=h21ff451_1 78 | - vs2015_runtime=14.27.29016=h5e58377_2 79 | - wheel=0.36.2=pyhd3eb1b0_0 80 | - wincertstore=0.2=py39h2bbff1b_0 81 | - xz=5.2.5=h62dcd97_0 82 | - yaml=0.2.5=he774522_0 83 | - zict=2.0.0=pyhd3eb1b0_0 84 | - zipp=3.5.0=pyhd3eb1b0_0 85 | - zlib=1.2.11=h62dcd97_4 86 | - zstd=1.4.9=h19a0ad4_0 87 | - pip: 88 | - tmm==0.1.8 89 | prefix: C:\Users\USERNAME\AppData\Local\Continuum\anaconda3\envs\mltf 90 | -------------------------------------------------------------------------------- /tmm_fast/gym_multilayerthinfilm/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def get_n_from_txt(filepath, points=None, lambda_min=400, lambda_max=700, complex_n=True): 4 | ntxt = np.loadtxt(filepath) 5 | if np.min(np.abs(ntxt[:, 0] - lambda_min)) > 25 or np.min(np.abs(ntxt[:, 0] - lambda_max)) > 25: 6 | print('No measurement data for refractive indicies are available within 25 nm in \n' + filepath) 7 | if points is None: 8 | points = lambda_max - lambda_min + 1 9 | idxmin = np.argmin(np.abs(ntxt[:, 0] - lambda_min)) 10 | idxmax = np.argmin(np.abs(ntxt[:, 0] - lambda_max)) 11 | if idxmax == idxmin: 12 | if complex_n: 13 | indicies = np.vectorize(complex)(np.array([ntxt[idxmin, 1]]), np.array([ntxt[idxmin, 2]])) 14 | else: 15 | indicies = np.array([ntxt[idxmin, 1]]) 16 | else: 17 | xp = ntxt[idxmin:idxmax, 0] 18 | fpn = ntxt[idxmin:idxmax, 1] 19 | n = np.interp(np.linspace(lambda_min, lambda_max, points), xp, fpn) 20 | if complex_n: 21 | fpk = ntxt[idxmin:idxmax, 2].squeeze() 22 | k = np.interp(np.linspace(lambda_min, lambda_max, points), xp, fpk) 23 | indicies = np.vectorize(complex)(n, k) 24 | else: 25 | indicies = n 26 | return indicies 27 | 28 | def get_N(path_list, lambda_min, lambda_max, points=None, complex_n=False): 29 | n = [] 30 | for path in path_list: 31 | n.append(get_n_from_txt(path, points, lambda_min=lambda_min, lambda_max=lambda_max, complex_n=complex_n)) 32 | return np.vstack((n)) 33 | -------------------------------------------------------------------------------- /tmm_fast/materials/nAu.txt: -------------------------------------------------------------------------------- 1 | 245.0 1.243946 1.344761 2 | 246.0 1.245431 1.351105 3 | 247.0 1.246945 1.357359 4 | 248.0 1.248519 1.363502 5 | 249.0 1.250182 1.369514 6 | 250.0 1.251962 1.375379 7 | 251.0 1.253877 1.381098 8 | 252.0 1.255924 1.386754 9 | 253.0 1.258093 1.392439 10 | 254.0 1.260375 1.398240 11 | 255.0 1.262765 1.404242 12 | 256.0 1.265259 1.410500 13 | 257.0 1.267889 1.416950 14 | 258.0 1.270693 1.423481 15 | 259.0 1.273708 1.429991 16 | 260.0 1.276969 1.436383 17 | 261.0 1.280505 1.442568 18 | 262.0 1.284321 1.448519 19 | 263.0 1.288396 1.454271 20 | 264.0 1.292710 1.459865 21 | 265.0 1.297241 1.465335 22 | 266.0 1.301971 1.470716 23 | 267.0 1.306882 1.476031 24 | 268.0 1.311965 1.481233 25 | 269.0 1.317214 1.486250 26 | 270.0 1.322625 1.491016 27 | 271.0 1.328191 1.495468 28 | 272.0 1.333909 1.499547 29 | 273.0 1.339761 1.503206 30 | 274.0 1.345673 1.506443 31 | 275.0 1.351556 1.509265 32 | 276.0 1.357327 1.511681 33 | 277.0 1.362908 1.513698 34 | 278.0 1.368226 1.515322 35 | 279.0 1.373220 1.516568 36 | 280.0 1.377901 1.517511 37 | 281.0 1.382309 1.518253 38 | 282.0 1.386480 1.518890 39 | 283.0 1.390451 1.519511 40 | 284.0 1.394253 1.520205 41 | 285.0 1.397919 1.521053 42 | 286.0 1.401466 1.522078 43 | 287.0 1.404894 1.523224 44 | 288.0 1.408206 1.524438 45 | 289.0 1.411402 1.525663 46 | 290.0 1.414484 1.526849 47 | 291.0 1.417452 1.527948 48 | 292.0 1.420308 1.528915 49 | 293.0 1.423064 1.529750 50 | 294.0 1.425735 1.530478 51 | 295.0 1.428335 1.531123 52 | 296.0 1.430880 1.531710 53 | 297.0 1.433382 1.532260 54 | 298.0 1.435855 1.532796 55 | 299.0 1.438311 1.533337 56 | 300.0 1.440750 1.533888 57 | 301.0 1.443168 1.534443 58 | 302.0 1.445557 1.534994 59 | 303.0 1.447912 1.535536 60 | 304.0 1.450228 1.536062 61 | 305.0 1.452500 1.536566 62 | 306.0 1.454722 1.537044 63 | 307.0 1.456894 1.537489 64 | 308.0 1.459027 1.537897 65 | 309.0 1.461131 1.538263 66 | 310.0 1.463217 1.538585 67 | 311.0 1.465295 1.538857 68 | 312.0 1.467374 1.539076 69 | 313.0 1.469464 1.539239 70 | 314.0 1.471573 1.539343 71 | 315.0 1.473696 1.539383 72 | 316.0 1.475810 1.539357 73 | 317.0 1.477891 1.539261 74 | 318.0 1.479916 1.539092 75 | 319.0 1.481866 1.538848 76 | 320.0 1.483719 1.538524 77 | 321.0 1.485454 1.538117 78 | 322.0 1.487055 1.537626 79 | 323.0 1.488511 1.537045 80 | 324.0 1.489835 1.536368 81 | 325.0 1.491039 1.535590 82 | 326.0 1.492138 1.534703 83 | 327.0 1.493142 1.533703 84 | 328.0 1.494066 1.532583 85 | 329.0 1.494919 1.531338 86 | 330.0 1.495715 1.529963 87 | 331.0 1.496461 1.528453 88 | 332.0 1.497145 1.526816 89 | 333.0 1.497736 1.525066 90 | 334.0 1.498201 1.523218 91 | 335.0 1.498512 1.521285 92 | 336.0 1.498639 1.519281 93 | 337.0 1.498555 1.517218 94 | 338.0 1.498232 1.515109 95 | 339.0 1.497645 1.512965 96 | 340.0 1.496767 1.510799 97 | 341.0 1.495592 1.508637 98 | 342.0 1.494128 1.506521 99 | 343.0 1.492383 1.504493 100 | 344.0 1.490368 1.502592 101 | 345.0 1.488090 1.500857 102 | 346.0 1.485557 1.499327 103 | 347.0 1.482779 1.498039 104 | 348.0 1.479764 1.497028 105 | 349.0 1.476520 1.496329 106 | 350.0 1.473060 1.495971 107 | 351.0 1.469423 1.495947 108 | 352.0 1.465659 1.496238 109 | 353.0 1.461813 1.496826 110 | 354.0 1.457932 1.497690 111 | 355.0 1.454060 1.498814 112 | 356.0 1.450241 1.500177 113 | 357.0 1.446516 1.501763 114 | 358.0 1.442925 1.503552 115 | 359.0 1.439508 1.505527 116 | 360.0 1.436300 1.507671 117 | 361.0 1.433306 1.509962 118 | 362.0 1.430514 1.512383 119 | 363.0 1.427914 1.514914 120 | 364.0 1.425492 1.517536 121 | 365.0 1.423237 1.520232 122 | 366.0 1.421139 1.522986 123 | 367.0 1.419185 1.525779 124 | 368.0 1.417365 1.528598 125 | 369.0 1.415668 1.531425 126 | 370.0 1.414084 1.534247 127 | 371.0 1.412602 1.537050 128 | 372.0 1.411215 1.539825 129 | 373.0 1.409915 1.542566 130 | 374.0 1.408695 1.545266 131 | 375.0 1.407550 1.547919 132 | 376.0 1.406471 1.550519 133 | 377.0 1.405454 1.553061 134 | 378.0 1.404490 1.555539 135 | 379.0 1.403575 1.557947 136 | 380.0 1.402703 1.560281 137 | 381.0 1.401867 1.562536 138 | 382.0 1.401062 1.564707 139 | 383.0 1.400284 1.566796 140 | 384.0 1.399529 1.568811 141 | 385.0 1.398795 1.570760 142 | 386.0 1.398078 1.572649 143 | 387.0 1.397376 1.574488 144 | 388.0 1.396687 1.576283 145 | 389.0 1.396006 1.578042 146 | 390.0 1.395333 1.579771 147 | 391.0 1.394664 1.581476 148 | 392.0 1.393998 1.583166 149 | 393.0 1.393332 1.584845 150 | 394.0 1.392665 1.586520 151 | 395.0 1.391993 1.588192 152 | 396.0 1.391313 1.589854 153 | 397.0 1.390623 1.591497 154 | 398.0 1.389919 1.593113 155 | 399.0 1.389197 1.594694 156 | 400.0 1.388455 1.596232 157 | 401.0 1.387690 1.597720 158 | 402.0 1.386899 1.599151 159 | 403.0 1.386078 1.600517 160 | 404.0 1.385226 1.601813 161 | 405.0 1.384340 1.603031 162 | 406.0 1.383417 1.604166 163 | 407.0 1.382453 1.605210 164 | 408.0 1.381449 1.606164 165 | 409.0 1.380404 1.607032 166 | 410.0 1.379321 1.607824 167 | 411.0 1.378200 1.608545 168 | 412.0 1.377042 1.609204 169 | 413.0 1.375848 1.609807 170 | 414.0 1.374620 1.610361 171 | 415.0 1.373359 1.610872 172 | 416.0 1.372065 1.611347 173 | 417.0 1.370740 1.611792 174 | 418.0 1.369385 1.612213 175 | 419.0 1.368001 1.612616 176 | 420.0 1.366589 1.613007 177 | 421.0 1.365149 1.613390 178 | 422.0 1.363683 1.613766 179 | 423.0 1.362187 1.614125 180 | 424.0 1.360661 1.614457 181 | 425.0 1.359101 1.614754 182 | 426.0 1.357507 1.615005 183 | 427.0 1.355876 1.615202 184 | 428.0 1.354206 1.615336 185 | 429.0 1.352497 1.615399 186 | 430.0 1.350744 1.615382 187 | 431.0 1.348949 1.615277 188 | 432.0 1.347107 1.615077 189 | 433.0 1.345218 1.614774 190 | 434.0 1.343280 1.614361 191 | 435.0 1.341292 1.613829 192 | 436.0 1.339250 1.613174 193 | 437.0 1.337154 1.612393 194 | 438.0 1.334999 1.611495 195 | 439.0 1.332781 1.610485 196 | 440.0 1.330497 1.609371 197 | 441.0 1.328143 1.608158 198 | 442.0 1.325716 1.606854 199 | 443.0 1.323212 1.605465 200 | 444.0 1.320628 1.603997 201 | 445.0 1.317960 1.602455 202 | 446.0 1.315206 1.600845 203 | 447.0 1.312363 1.599174 204 | 448.0 1.309427 1.597447 205 | 449.0 1.306395 1.595670 206 | 450.0 1.303265 1.593847 207 | 451.0 1.300034 1.591984 208 | 452.0 1.296698 1.590086 209 | 453.0 1.293250 1.588151 210 | 454.0 1.289678 1.586167 211 | 455.0 1.285972 1.584125 212 | 456.0 1.282119 1.582015 213 | 457.0 1.278109 1.579825 214 | 458.0 1.273929 1.577548 215 | 459.0 1.269569 1.575173 216 | 460.0 1.265019 1.572692 217 | 461.0 1.260266 1.570095 218 | 462.0 1.255301 1.567374 219 | 463.0 1.250112 1.564519 220 | 464.0 1.244688 1.561523 221 | 465.0 1.239019 1.558377 222 | 466.0 1.233094 1.555073 223 | 467.0 1.226901 1.551603 224 | 468.0 1.220431 1.547960 225 | 469.0 1.213671 1.544135 226 | 470.0 1.206610 1.540138 227 | 471.0 1.199239 1.536002 228 | 472.0 1.191545 1.531760 229 | 473.0 1.183519 1.527448 230 | 474.0 1.175151 1.523100 231 | 475.0 1.166430 1.518749 232 | 476.0 1.157346 1.514431 233 | 477.0 1.147890 1.510179 234 | 478.0 1.138051 1.506029 235 | 479.0 1.127820 1.502014 236 | 480.0 1.117190 1.498171 237 | 481.0 1.106151 1.494535 238 | 482.0 1.094695 1.491141 239 | 483.0 1.082815 1.488026 240 | 484.0 1.070507 1.485227 241 | 485.0 1.057762 1.482782 242 | 486.0 1.044579 1.480728 243 | 487.0 1.030954 1.479104 244 | 488.0 1.016889 1.477947 245 | 489.0 1.002409 1.477272 246 | 490.0 0.987553 1.477089 247 | 491.0 0.972359 1.477404 248 | 492.0 0.956864 1.478224 249 | 493.0 0.941110 1.479556 250 | 494.0 0.925135 1.481404 251 | 495.0 0.908981 1.483772 252 | 496.0 0.892690 1.486661 253 | 497.0 0.876303 1.490073 254 | 498.0 0.859862 1.494007 255 | 499.0 0.843408 1.498460 256 | 500.0 0.826986 1.503426 257 | 501.0 0.810635 1.508900 258 | 502.0 0.794396 1.514873 259 | 503.0 0.778312 1.521335 260 | 504.0 0.762420 1.528272 261 | 505.0 0.746759 1.535670 262 | 506.0 0.731368 1.543513 263 | 507.0 0.716279 1.551784 264 | 508.0 0.701526 1.560462 265 | 509.0 0.687120 1.569525 266 | 510.0 0.673061 1.578948 267 | 511.0 0.659347 1.588708 268 | 512.0 0.645979 1.598782 269 | 513.0 0.632952 1.609145 270 | 514.0 0.620262 1.619777 271 | 515.0 0.607906 1.630654 272 | 516.0 0.595877 1.641757 273 | 517.0 0.584170 1.653063 274 | 518.0 0.572776 1.664553 275 | 519.0 0.561689 1.676209 276 | 520.0 0.550901 1.688011 277 | 521.0 0.540403 1.699943 278 | 522.0 0.530186 1.711988 279 | 523.0 0.520240 1.724131 280 | 524.0 0.510557 1.736356 281 | 525.0 0.501128 1.748648 282 | 526.0 0.491941 1.760996 283 | 527.0 0.482987 1.773386 284 | 528.0 0.474257 1.785807 285 | 529.0 0.465741 1.798246 286 | 530.0 0.457430 1.810695 287 | 531.0 0.449319 1.823150 288 | 532.0 0.441406 1.835604 289 | 533.0 0.433686 1.848056 290 | 534.0 0.426156 1.860501 291 | 535.0 0.418812 1.872936 292 | 536.0 0.411652 1.885359 293 | 537.0 0.404670 1.897766 294 | 538.0 0.397865 1.910156 295 | 539.0 0.391233 1.922524 296 | 540.0 0.384769 1.934870 297 | 541.0 0.378471 1.947191 298 | 542.0 0.372336 1.959484 299 | 543.0 0.366360 1.971750 300 | 544.0 0.360539 1.983984 301 | 545.0 0.354871 1.996186 302 | 546.0 0.349353 2.008355 303 | 547.0 0.343980 2.020489 304 | 548.0 0.338751 2.032586 305 | 549.0 0.333663 2.044646 306 | 550.0 0.328711 2.056668 307 | 551.0 0.323894 2.068650 308 | 552.0 0.319209 2.080593 309 | 553.0 0.314653 2.092494 310 | 554.0 0.310223 2.104353 311 | 555.0 0.305913 2.116169 312 | 556.0 0.301720 2.127943 313 | 557.0 0.297639 2.139672 314 | 558.0 0.293666 2.151357 315 | 559.0 0.289797 2.162997 316 | 560.0 0.286027 2.174591 317 | 561.0 0.282353 2.186140 318 | 562.0 0.278772 2.197642 319 | 563.0 0.275279 2.209098 320 | 564.0 0.271870 2.220508 321 | 565.0 0.268544 2.231871 322 | 566.0 0.265296 2.243187 323 | 567.0 0.262122 2.254457 324 | 568.0 0.259021 2.265679 325 | 569.0 0.255989 2.276855 326 | 570.0 0.253023 2.287984 327 | 571.0 0.250120 2.299066 328 | 572.0 0.247277 2.310102 329 | 573.0 0.244493 2.321091 330 | 574.0 0.241764 2.332034 331 | 575.0 0.239089 2.342931 332 | 576.0 0.236463 2.353782 333 | 577.0 0.233887 2.364586 334 | 578.0 0.231356 2.375345 335 | 579.0 0.228869 2.386059 336 | 580.0 0.226424 2.396727 337 | 581.0 0.224021 2.407351 338 | 582.0 0.221659 2.417933 339 | 583.0 0.219336 2.428470 340 | 584.0 0.217053 2.438967 341 | 585.0 0.214808 2.449421 342 | 586.0 0.212600 2.459836 343 | 587.0 0.210430 2.470210 344 | 588.0 0.208296 2.480545 345 | 589.0 0.206197 2.490841 346 | 590.0 0.204134 2.501100 347 | 591.0 0.202105 2.511321 348 | 592.0 0.200110 2.521505 349 | 593.0 0.198148 2.531654 350 | 594.0 0.196219 2.541766 351 | 595.0 0.194322 2.551843 352 | 596.0 0.192456 2.561887 353 | 597.0 0.190621 2.571897 354 | 598.0 0.188817 2.581872 355 | 599.0 0.187043 2.591816 356 | 600.0 0.185299 2.601727 357 | 601.0 0.183583 2.611606 358 | 602.0 0.181896 2.621454 359 | 603.0 0.180237 2.631270 360 | 604.0 0.178606 2.641057 361 | 605.0 0.177002 2.650814 362 | 606.0 0.175425 2.660541 363 | 607.0 0.173874 2.670239 364 | 608.0 0.172349 2.679908 365 | 609.0 0.170849 2.689549 366 | 610.0 0.169374 2.699163 367 | 611.0 0.167923 2.708749 368 | 612.0 0.166494 2.718310 369 | 613.0 0.165088 2.727844 370 | 614.0 0.163703 2.737353 371 | 615.0 0.162339 2.746837 372 | 616.0 0.160996 2.756296 373 | 617.0 0.159672 2.765732 374 | 618.0 0.158367 2.775143 375 | 619.0 0.157080 2.784533 376 | 620.0 0.155811 2.793899 377 | 621.0 0.154560 2.803243 378 | 622.0 0.153325 2.812566 379 | 623.0 0.152106 2.821867 380 | 624.0 0.150903 2.831147 381 | 625.0 0.149715 2.840407 382 | 626.0 0.148541 2.849647 383 | 627.0 0.147382 2.858866 384 | 628.0 0.146236 2.868067 385 | 629.0 0.145103 2.877249 386 | 630.0 0.143984 2.886411 387 | 631.0 0.142876 2.895555 388 | 632.0 0.141781 2.904681 389 | 633.0 0.140696 2.913790 390 | 634.0 0.139623 2.922881 391 | 635.0 0.138561 2.931955 392 | 636.0 0.137509 2.941011 393 | 637.0 0.136467 2.950052 394 | 638.0 0.135434 2.959076 395 | 639.0 0.134411 2.968085 396 | 640.0 0.133397 2.977077 397 | 641.0 0.132392 2.986054 398 | 642.0 0.131398 2.995016 399 | 643.0 0.130413 3.003964 400 | 644.0 0.129439 3.012898 401 | 645.0 0.128476 3.021817 402 | 646.0 0.127525 3.030723 403 | 647.0 0.126584 3.039616 404 | 648.0 0.125656 3.048496 405 | 649.0 0.124740 3.057363 406 | 650.0 0.123836 3.066218 407 | 651.0 0.122945 3.075061 408 | 652.0 0.122068 3.083892 409 | 653.0 0.121203 3.092712 410 | 654.0 0.120352 3.101520 411 | 655.0 0.119514 3.110317 412 | 656.0 0.118691 3.119104 413 | 657.0 0.117881 3.127881 414 | 658.0 0.117086 3.136646 415 | 659.0 0.116306 3.145402 416 | 660.0 0.115540 3.154148 417 | 661.0 0.114789 3.162884 418 | 662.0 0.114054 3.171611 419 | 663.0 0.113333 3.180328 420 | 664.0 0.112628 3.189036 421 | 665.0 0.111939 3.197735 422 | 666.0 0.111266 3.206426 423 | 667.0 0.110608 3.215108 424 | 668.0 0.109966 3.223781 425 | 669.0 0.109341 3.232447 426 | 670.0 0.108732 3.241104 427 | 671.0 0.108139 3.249753 428 | 672.0 0.107562 3.258394 429 | 673.0 0.107003 3.267028 430 | 674.0 0.106459 3.275654 431 | 675.0 0.105933 3.284272 432 | 676.0 0.105422 3.292883 433 | 677.0 0.104928 3.301484 434 | 678.0 0.104449 3.310077 435 | 679.0 0.103984 3.318661 436 | 680.0 0.103535 3.327235 437 | 681.0 0.103100 3.335799 438 | 682.0 0.102678 3.344352 439 | 683.0 0.102271 3.352895 440 | 684.0 0.101876 3.361428 441 | 685.0 0.101495 3.369948 442 | 686.0 0.101126 3.378457 443 | 687.0 0.100769 3.386954 444 | 688.0 0.100425 3.395438 445 | 689.0 0.100091 3.403911 446 | 690.0 0.099770 3.412370 447 | 691.0 0.099459 3.420816 448 | 692.0 0.099159 3.429249 449 | 693.0 0.098870 3.437668 450 | 694.0 0.098590 3.446073 451 | 695.0 0.098321 3.454464 452 | 696.0 0.098061 3.462841 453 | 697.0 0.097811 3.471203 454 | 698.0 0.097570 3.479550 455 | 699.0 0.097338 3.487882 456 | 700.0 0.097114 3.496199 457 | 701.0 0.096899 3.504500 458 | 702.0 0.096691 3.512786 459 | 703.0 0.096492 3.521056 460 | 704.0 0.096301 3.529310 461 | 705.0 0.096117 3.537548 462 | 706.0 0.095940 3.545769 463 | 707.0 0.095770 3.553974 464 | 708.0 0.095607 3.562162 465 | 709.0 0.095450 3.570333 466 | 710.0 0.095300 3.578488 467 | 711.0 0.095157 3.586625 468 | 712.0 0.095019 3.594745 469 | 713.0 0.094887 3.602847 470 | 714.0 0.094761 3.610932 471 | 715.0 0.094640 3.619000 472 | 716.0 0.094524 3.627051 473 | 717.0 0.094414 3.635086 474 | 718.0 0.094309 3.643105 475 | 719.0 0.094209 3.651109 476 | 720.0 0.094113 3.659096 477 | 721.0 0.094022 3.667069 478 | 722.0 0.093936 3.675027 479 | 723.0 0.093854 3.682971 480 | 724.0 0.093776 3.690900 481 | 725.0 0.093703 3.698816 482 | 726.0 0.093633 3.706717 483 | 727.0 0.093567 3.714606 484 | 728.0 0.093505 3.722481 485 | 729.0 0.093447 3.730343 486 | 730.0 0.093392 3.738194 487 | 731.0 0.093341 3.746031 488 | 732.0 0.093293 3.753856 489 | 733.0 0.093248 3.761670 490 | 734.0 0.093206 3.769471 491 | 735.0 0.093167 3.777262 492 | 736.0 0.093131 3.785041 493 | 737.0 0.093098 3.792809 494 | 738.0 0.093068 3.800566 495 | 739.0 0.093040 3.808313 496 | 740.0 0.093015 3.816049 497 | 741.0 0.092992 3.823775 498 | 742.0 0.092971 3.831491 499 | 743.0 0.092953 3.839197 500 | 744.0 0.092937 3.846894 501 | 745.0 0.092923 3.854581 502 | 746.0 0.092911 3.862258 503 | 747.0 0.092901 3.869927 504 | 748.0 0.092893 3.877586 505 | 749.0 0.092886 3.885237 506 | 750.0 0.092882 3.892879 507 | 751.0 0.092878 3.900513 508 | 752.0 0.092877 3.908138 509 | 753.0 0.092877 3.915755 510 | 754.0 0.092878 3.923364 511 | 755.0 0.092881 3.930965 512 | 756.0 0.092884 3.938558 513 | 757.0 0.092890 3.946143 514 | 758.0 0.092896 3.953721 515 | 759.0 0.092903 3.961291 516 | 760.0 0.092912 3.968854 517 | 761.0 0.092922 3.976409 518 | 762.0 0.092933 3.983957 519 | 763.0 0.092945 3.991497 520 | 764.0 0.092958 3.999030 521 | 765.0 0.092972 4.006555 522 | 766.0 0.092988 4.014073 523 | 767.0 0.093004 4.021585 524 | 768.0 0.093022 4.029088 525 | 769.0 0.093041 4.036584 526 | 770.0 0.093061 4.044074 527 | 771.0 0.093081 4.051556 528 | 772.0 0.093103 4.059031 529 | 773.0 0.093126 4.066498 530 | 774.0 0.093150 4.073959 531 | 775.0 0.093175 4.081412 532 | 776.0 0.093201 4.088859 533 | 777.0 0.093228 4.096298 534 | 778.0 0.093256 4.103731 535 | 779.0 0.093285 4.111156 536 | 780.0 0.093315 4.118575 537 | 781.0 0.093346 4.125986 538 | 782.0 0.093378 4.133390 539 | 783.0 0.093410 4.140788 540 | 784.0 0.093444 4.148179 541 | 785.0 0.093479 4.155563 542 | 786.0 0.093514 4.162940 543 | 787.0 0.093551 4.170310 544 | 788.0 0.093588 4.177673 545 | 789.0 0.093627 4.185030 546 | 790.0 0.093666 4.192379 547 | 791.0 0.093706 4.199722 548 | 792.0 0.093747 4.207058 549 | 793.0 0.093789 4.214388 550 | 794.0 0.093832 4.221710 551 | 795.0 0.093875 4.229026 552 | 796.0 0.093920 4.236335 553 | 797.0 0.093965 4.243638 554 | 798.0 0.094011 4.250934 555 | 799.0 0.094058 4.258223 556 | 800.0 0.094106 4.265505 557 | 801.0 0.094154 4.272780 558 | 802.0 0.094204 4.280050 559 | 803.0 0.094254 4.287312 560 | 804.0 0.094305 4.294568 561 | 805.0 0.094357 4.301816 562 | 806.0 0.094409 4.309059 563 | 807.0 0.094462 4.316295 564 | 808.0 0.094516 4.323524 565 | 809.0 0.094571 4.330748 566 | 810.0 0.094627 4.337964 567 | 811.0 0.094683 4.345175 568 | 812.0 0.094740 4.352379 569 | 813.0 0.094798 4.359578 570 | 814.0 0.094856 4.366770 571 | 815.0 0.094916 4.373957 572 | 816.0 0.094976 4.381138 573 | 817.0 0.095036 4.388313 574 | 818.0 0.095098 4.395483 575 | 819.0 0.095160 4.402647 576 | 820.0 0.095223 4.409807 577 | 821.0 0.095287 4.416961 578 | 822.0 0.095351 4.424109 579 | 823.0 0.095416 4.431252 580 | 824.0 0.095482 4.438391 581 | 825.0 0.095549 4.445525 582 | 826.0 0.095616 4.452653 583 | 827.0 0.095684 4.459777 584 | 828.0 0.095752 4.466896 585 | 829.0 0.095822 4.474010 586 | 830.0 0.095892 4.481119 587 | 831.0 0.095962 4.488225 588 | 832.0 0.096034 4.495325 589 | 833.0 0.096106 4.502420 590 | 834.0 0.096179 4.509512 591 | 835.0 0.096252 4.516600 592 | 836.0 0.096326 4.523682 593 | 837.0 0.096401 4.530761 594 | 838.0 0.096476 4.537836 595 | 839.0 0.096552 4.544906 596 | 840.0 0.096629 4.551972 597 | 841.0 0.096707 4.559034 598 | 842.0 0.096785 4.566092 599 | 843.0 0.096863 4.573147 600 | 844.0 0.096943 4.580197 601 | 845.0 0.097023 4.587244 602 | 846.0 0.097103 4.594286 603 | 847.0 0.097185 4.601325 604 | 848.0 0.097266 4.608360 605 | 849.0 0.097349 4.615391 606 | 850.0 0.097432 4.622419 607 | 851.0 0.097516 4.629443 608 | 852.0 0.097600 4.636464 609 | 853.0 0.097685 4.643481 610 | 854.0 0.097771 4.650494 611 | 855.0 0.097857 4.657504 612 | 856.0 0.097944 4.664510 613 | 857.0 0.098031 4.671513 614 | 858.0 0.098119 4.678512 615 | 859.0 0.098208 4.685508 616 | 860.0 0.098297 4.692501 617 | 861.0 0.098387 4.699490 618 | 862.0 0.098477 4.706476 619 | 863.0 0.098568 4.713459 620 | 864.0 0.098660 4.720438 621 | 865.0 0.098752 4.727414 622 | 866.0 0.098844 4.734387 623 | 867.0 0.098938 4.741356 624 | 868.0 0.099031 4.748322 625 | 869.0 0.099126 4.755285 626 | 870.0 0.099221 4.762245 627 | 871.0 0.099316 4.769201 628 | 872.0 0.099412 4.776154 629 | 873.0 0.099509 4.783103 630 | 874.0 0.099606 4.790049 631 | 875.0 0.099704 4.796992 632 | 876.0 0.099802 4.803931 633 | 877.0 0.099901 4.810867 634 | 878.0 0.100001 4.817800 635 | 879.0 0.100101 4.824729 636 | 880.0 0.100201 4.831655 637 | 881.0 0.100303 4.838578 638 | 882.0 0.100404 4.845496 639 | 883.0 0.100507 4.852412 640 | 884.0 0.100609 4.859324 641 | 885.0 0.100713 4.866233 642 | 886.0 0.100817 4.873138 643 | 887.0 0.100921 4.880040 644 | 888.0 0.101026 4.886939 645 | 889.0 0.101132 4.893833 646 | 890.0 0.101238 4.900724 647 | 891.0 0.101345 4.907612 648 | 892.0 0.101452 4.914497 649 | 893.0 0.101559 4.921378 650 | 894.0 0.101668 4.928255 651 | 895.0 0.101777 4.935129 652 | 896.0 0.101886 4.941999 653 | 897.0 0.101996 4.948866 654 | 898.0 0.102106 4.955729 655 | 899.0 0.102217 4.962589 656 | 900.0 0.102328 4.969445 657 | 901.0 0.102440 4.976297 658 | 902.0 0.102553 4.983146 659 | 903.0 0.102666 4.989991 660 | 904.0 0.102779 4.996832 661 | 905.0 0.102894 5.003671 662 | 906.0 0.103008 5.010505 663 | 907.0 0.103123 5.017335 664 | 908.0 0.103239 5.024163 665 | 909.0 0.103355 5.030985 666 | 910.0 0.103471 5.037805 667 | 911.0 0.103588 5.044621 668 | 912.0 0.103706 5.051433 669 | 913.0 0.103824 5.058241 670 | 914.0 0.103943 5.065046 671 | 915.0 0.104062 5.071847 672 | 916.0 0.104181 5.078644 673 | 917.0 0.104301 5.085437 674 | 918.0 0.104422 5.092227 675 | 919.0 0.104543 5.099012 676 | 920.0 0.104664 5.105794 677 | 921.0 0.104786 5.112573 678 | 922.0 0.104909 5.119347 679 | 923.0 0.105032 5.126117 680 | 924.0 0.105155 5.132884 681 | 925.0 0.105279 5.139647 682 | 926.0 0.105403 5.146405 683 | 927.0 0.105528 5.153160 684 | 928.0 0.105653 5.159911 685 | 929.0 0.105779 5.166658 686 | 930.0 0.105905 5.173402 687 | 931.0 0.106032 5.180142 688 | 932.0 0.106159 5.186879 689 | 933.0 0.106286 5.193613 690 | 934.0 0.106414 5.200344 691 | 935.0 0.106543 5.207072 692 | 936.0 0.106671 5.213798 693 | 937.0 0.106801 5.220521 694 | 938.0 0.106930 5.227242 695 | 939.0 0.107060 5.233960 696 | 940.0 0.107191 5.240677 697 | 941.0 0.107322 5.247391 698 | 942.0 0.107453 5.254104 699 | 943.0 0.107585 5.260816 700 | 944.0 0.107717 5.267525 701 | 945.0 0.107850 5.274233 702 | 946.0 0.107983 5.280941 703 | 947.0 0.108116 5.287646 704 | 948.0 0.108250 5.294351 705 | 949.0 0.108384 5.301055 706 | 950.0 0.108519 5.307758 707 | 951.0 0.108654 5.314461 708 | 952.0 0.108789 5.321163 709 | 953.0 0.108925 5.327864 710 | 954.0 0.109061 5.334565 711 | 955.0 0.109197 5.341265 712 | 956.0 0.109334 5.347966 713 | 957.0 0.109471 5.354666 714 | 958.0 0.109609 5.361367 715 | 959.0 0.109747 5.368068 716 | 960.0 0.109885 5.374769 717 | 961.0 0.110024 5.381470 718 | 962.0 0.110163 5.388171 719 | 963.0 0.110302 5.394873 720 | 964.0 0.110442 5.401575 721 | 965.0 0.110582 5.408278 722 | 966.0 0.110722 5.414983 723 | 967.0 0.110863 5.421687 724 | 968.0 0.111004 5.428392 725 | 969.0 0.111145 5.435099 726 | 970.0 0.111287 5.441806 727 | 971.0 0.111429 5.448514 728 | 972.0 0.111571 5.455224 729 | 973.0 0.111714 5.461935 730 | 974.0 0.111857 5.468647 731 | 975.0 0.112000 5.475359 732 | 976.0 0.112144 5.482074 733 | 977.0 0.112288 5.488791 734 | 978.0 0.112432 5.495508 735 | 979.0 0.112577 5.502227 736 | 980.0 0.112722 5.508948 737 | 981.0 0.112867 5.515671 738 | 982.0 0.113012 5.522395 739 | 983.0 0.113158 5.529120 740 | 984.0 0.113304 5.535848 741 | 985.0 0.113450 5.542578 742 | 986.0 0.113597 5.549309 743 | 987.0 0.113744 5.556043 744 | 988.0 0.113891 5.562778 745 | 989.0 0.114038 5.569516 746 | 990.0 0.114186 5.576255 747 | 991.0 0.114334 5.582996 748 | 992.0 0.114482 5.589740 749 | 993.0 0.114630 5.596487 750 | 994.0 0.114779 5.603234 751 | 995.0 0.114928 5.609984 752 | 996.0 0.115077 5.616737 753 | 997.0 0.115227 5.623493 754 | 998.0 0.115377 5.630250 755 | 999.0 0.115527 5.637010 756 | 1000.0 0.115677 5.643771 757 | 1002.5 0.116054 5.660687 758 | 1005.0 0.116432 5.677619 759 | 1007.5 0.116811 5.694562 760 | 1010.0 0.117192 5.711518 761 | 1012.5 0.117574 5.728482 762 | 1015.0 0.117957 5.745453 763 | 1017.5 0.118342 5.762429 764 | 1020.0 0.118727 5.779408 765 | 1022.5 0.119113 5.796388 766 | 1025.0 0.119500 5.813367 767 | 1027.5 0.119888 5.830344 768 | 1030.0 0.120277 5.847317 769 | 1032.5 0.120666 5.864284 770 | 1035.0 0.121056 5.881243 771 | 1037.5 0.121446 5.898193 772 | 1040.0 0.121837 5.915133 773 | 1042.5 0.122228 5.932062 774 | 1045.0 0.122619 5.948977 775 | 1047.5 0.123011 5.965877 776 | 1050.0 0.123403 5.982760 777 | 1052.5 0.123795 5.999628 778 | 1055.0 0.124188 6.016476 779 | 1057.5 0.124580 6.033305 780 | 1060.0 0.124973 6.050113 781 | 1062.5 0.125365 6.066899 782 | 1065.0 0.125758 6.083662 783 | 1067.5 0.126150 6.100402 784 | 1070.0 0.126543 6.117116 785 | 1072.5 0.126935 6.133804 786 | 1075.0 0.127327 6.150465 787 | 1077.5 0.127719 6.167099 788 | 1080.0 0.128110 6.183703 789 | 1082.5 0.128501 6.200280 790 | 1085.0 0.128892 6.216824 791 | 1087.5 0.129282 6.233338 792 | 1090.0 0.129672 6.249821 793 | 1092.5 0.130062 6.266271 794 | 1095.0 0.130451 6.282689 795 | 1097.5 0.130840 6.299078 796 | 1100.0 0.131230 6.315437 797 | 1102.5 0.131619 6.331772 798 | 1105.0 0.132009 6.348081 799 | 1107.5 0.132399 6.364369 800 | 1110.0 0.132790 6.380635 801 | 1112.5 0.133181 6.396882 802 | 1115.0 0.133574 6.413111 803 | 1117.5 0.133967 6.429324 804 | 1120.0 0.134362 6.445523 805 | 1122.5 0.134759 6.461707 806 | 1125.0 0.135156 6.477879 807 | 1127.5 0.135555 6.494040 808 | 1130.0 0.135956 6.510191 809 | 1132.5 0.136359 6.526333 810 | 1135.0 0.136764 6.542468 811 | 1137.5 0.137170 6.558596 812 | 1140.0 0.137579 6.574719 813 | 1142.5 0.137990 6.590837 814 | 1145.0 0.138403 6.606951 815 | 1147.5 0.138818 6.623063 816 | 1150.0 0.139235 6.639172 817 | 1152.5 0.139656 6.655280 818 | 1155.0 0.140078 6.671388 819 | 1157.5 0.140503 6.687495 820 | 1160.0 0.140931 6.703604 821 | 1162.5 0.141362 6.719714 822 | 1165.0 0.141795 6.735826 823 | 1167.5 0.142231 6.751941 824 | 1170.0 0.142670 6.768059 825 | 1172.5 0.143112 6.784182 826 | 1175.0 0.143556 6.800307 827 | 1177.5 0.144004 6.816439 828 | 1180.0 0.144454 6.832575 829 | 1182.5 0.144908 6.848716 830 | 1185.0 0.145365 6.864864 831 | 1187.5 0.145825 6.881018 832 | 1190.0 0.146288 6.897179 833 | 1192.5 0.146754 6.913347 834 | 1195.0 0.147223 6.929522 835 | 1197.5 0.147695 6.945704 836 | 1200.0 0.148171 6.961895 837 | 1202.5 0.148649 6.978091 838 | 1205.0 0.149131 6.994293 839 | 1207.5 0.149615 7.010502 840 | 1210.0 0.150102 7.026713 841 | 1212.5 0.150592 7.042929 842 | 1215.0 0.151085 7.059147 843 | 1217.5 0.151580 7.075367 844 | 1220.0 0.152077 7.091589 845 | 1222.5 0.152577 7.107810 846 | 1225.0 0.153078 7.124032 847 | 1227.5 0.153582 7.140252 848 | 1230.0 0.154088 7.156471 849 | 1232.5 0.154596 7.172687 850 | 1235.0 0.155106 7.188900 851 | 1237.5 0.155618 7.205109 852 | 1240.0 0.156131 7.221314 853 | 1242.5 0.156646 7.237514 854 | 1245.0 0.157163 7.253709 855 | 1247.5 0.157681 7.269897 856 | 1250.0 0.158201 7.286079 857 | 1252.5 0.158722 7.302253 858 | 1255.0 0.159244 7.318419 859 | 1257.5 0.159768 7.334578 860 | 1260.0 0.160293 7.350726 861 | 1262.5 0.160819 7.366866 862 | 1265.0 0.161346 7.382995 863 | 1267.5 0.161874 7.399114 864 | 1270.0 0.162402 7.415222 865 | 1272.5 0.162932 7.431318 866 | 1275.0 0.163463 7.447402 867 | 1277.5 0.163994 7.463474 868 | 1280.0 0.164527 7.479534 869 | 1282.5 0.165059 7.495579 870 | 1285.0 0.165593 7.511611 871 | 1287.5 0.166127 7.527629 872 | 1290.0 0.166662 7.543633 873 | 1292.5 0.167197 7.559621 874 | 1295.0 0.167732 7.575595 875 | 1297.5 0.168268 7.591552 876 | 1300.0 0.168804 7.607493 877 | 1302.5 0.169341 7.623419 878 | 1305.0 0.169878 7.639327 879 | 1307.5 0.170415 7.655218 880 | 1310.0 0.170952 7.671091 881 | 1312.5 0.171490 7.686947 882 | 1315.0 0.172027 7.702785 883 | 1317.5 0.172565 7.718604 884 | 1320.0 0.173102 7.734405 885 | 1322.5 0.173640 7.750186 886 | 1325.0 0.174178 7.765948 887 | 1327.5 0.174715 7.781691 888 | 1330.0 0.175253 7.797415 889 | 1332.5 0.175790 7.813121 890 | 1335.0 0.176328 7.828812 891 | 1337.5 0.176866 7.844488 892 | 1340.0 0.177405 7.860151 893 | 1342.5 0.177944 7.875802 894 | 1345.0 0.178483 7.891443 895 | 1347.5 0.179023 7.907074 896 | 1350.0 0.179564 7.922698 897 | 1352.5 0.180106 7.938315 898 | 1355.0 0.180648 7.953927 899 | 1357.5 0.181191 7.969534 900 | 1360.0 0.181736 7.985138 901 | 1362.5 0.182281 8.000738 902 | 1365.0 0.182828 8.016338 903 | 1367.5 0.183375 8.031938 904 | 1370.0 0.183924 8.047538 905 | 1372.5 0.184474 8.063139 906 | 1375.0 0.185026 8.078743 907 | 1377.5 0.185579 8.094349 908 | 1380.0 0.186134 8.109959 909 | 1382.5 0.186690 8.125574 910 | 1385.0 0.187247 8.141194 911 | 1387.5 0.187806 8.156821 912 | 1390.0 0.188367 8.172455 913 | 1392.5 0.188929 8.188095 914 | 1395.0 0.189494 8.203744 915 | 1397.5 0.190059 8.219401 916 | 1400.0 0.190627 8.235067 917 | 1402.5 0.191197 8.250744 918 | 1405.0 0.191768 8.266431 919 | 1407.5 0.192341 8.282128 920 | 1410.0 0.192916 8.297837 921 | 1412.5 0.193493 8.313559 922 | 1415.0 0.194072 8.329291 923 | 1417.5 0.194653 8.345037 924 | 1420.0 0.195236 8.360795 925 | 1422.5 0.195821 8.376567 926 | 1425.0 0.196408 8.392353 927 | 1427.5 0.196997 8.408153 928 | 1430.0 0.197588 8.423967 929 | 1432.5 0.198181 8.439796 930 | 1435.0 0.198777 8.455641 931 | 1437.5 0.199374 8.471500 932 | 1440.0 0.199974 8.487376 933 | 1442.5 0.200575 8.503266 934 | 1445.0 0.201179 8.519174 935 | 1447.5 0.201785 8.535097 936 | 1450.0 0.202393 8.551037 937 | 1452.5 0.203003 8.566994 938 | 1455.0 0.203616 8.582967 939 | 1457.5 0.204230 8.598957 940 | 1460.0 0.204847 8.614964 941 | 1462.5 0.205466 8.630989 942 | 1465.0 0.206087 8.647031 943 | 1467.5 0.206711 8.663091 944 | 1470.0 0.207336 8.679168 945 | 1472.5 0.207964 8.695262 946 | 1475.0 0.208594 8.711374 947 | 1477.5 0.209226 8.727505 948 | 1480.0 0.209860 8.743652 949 | 1482.5 0.210496 8.759818 950 | 1485.0 0.211135 8.776002 951 | 1487.5 0.211775 8.792203 952 | 1490.0 0.212418 8.808421 953 | 1492.5 0.213063 8.824654 954 | 1495.0 0.213709 8.840899 955 | 1497.5 0.214357 8.857154 956 | 1500.0 0.215007 8.873417 957 | 1502.5 0.215658 8.889687 958 | 1505.0 0.216310 8.905959 959 | 1507.5 0.216964 8.922235 960 | 1510.0 0.217618 8.938510 961 | 1512.5 0.218274 8.954782 962 | 1515.0 0.218930 8.971052 963 | 1517.5 0.219587 8.987318 964 | 1520.0 0.220245 9.003575 965 | 1522.5 0.220903 9.019825 966 | 1525.0 0.221561 9.036063 967 | 1527.5 0.222219 9.052291 968 | 1530.0 0.222878 9.068504 969 | 1532.5 0.223537 9.084703 970 | 1535.0 0.224196 9.100885 971 | 1537.5 0.224855 9.117050 972 | 1540.0 0.225513 9.133196 973 | 1542.5 0.226171 9.149321 974 | 1545.0 0.226829 9.165423 975 | 1547.5 0.227487 9.181503 976 | 1550.0 0.228144 9.197558 977 | 1552.5 0.228800 9.213588 978 | 1555.0 0.229456 9.229590 979 | 1557.5 0.230111 9.245565 980 | 1560.0 0.230765 9.261511 981 | 1562.5 0.231418 9.277426 982 | 1565.0 0.232070 9.293309 983 | 1567.5 0.232721 9.309162 984 | 1570.0 0.233371 9.324980 985 | 1572.5 0.234020 9.340764 986 | 1575.0 0.234668 9.356512 987 | 1577.5 0.235314 9.372224 988 | 1580.0 0.235960 9.387899 989 | 1582.5 0.236603 9.403536 990 | 1585.0 0.237246 9.419134 991 | 1587.5 0.237887 9.434692 992 | 1590.0 0.238526 9.450211 993 | 1592.5 0.239164 9.465687 994 | 1595.0 0.239800 9.481121 995 | 1597.5 0.240434 9.496513 996 | 1600.0 0.241067 9.511861 997 | 1602.5 0.241698 9.527164 998 | 1605.0 0.242327 9.542423 999 | 1607.5 0.242955 9.557637 1000 | 1610.0 0.243580 9.572803 1001 | 1612.5 0.244204 9.587925 1002 | 1615.0 0.244825 9.602998 1003 | 1617.5 0.245445 9.618023 1004 | 1620.0 0.246062 9.632999 1005 | 1622.5 0.246678 9.647926 1006 | 1625.0 0.247291 9.662805 1007 | 1627.5 0.247902 9.677632 1008 | 1630.0 0.248511 9.692410 1009 | 1632.5 0.249118 9.707136 1010 | 1635.0 0.249723 9.721810 1011 | 1637.5 0.250325 9.736433 1012 | 1640.0 0.250926 9.751004 1013 | 1642.5 0.251523 9.765522 1014 | 1645.0 0.252119 9.779986 1015 | 1647.5 0.252712 9.794396 1016 | 1650.0 0.253303 9.808754 1017 | 1652.5 0.253891 9.823057 1018 | 1655.0 0.254477 9.837305 1019 | 1657.5 0.255061 9.851498 1020 | 1660.0 0.255642 9.865636 1021 | 1662.5 0.256221 9.879718 1022 | 1665.0 0.256797 9.893745 1023 | 1667.5 0.257371 9.907715 1024 | 1670.0 0.257942 9.921630 1025 | 1672.5 0.258510 9.935487 1026 | 1675.0 0.259076 9.949287 1027 | 1677.5 0.259640 9.963031 1028 | 1680.0 0.260201 9.976717 1029 | 1682.5 0.260759 9.990346 1030 | 1685.0 0.261315 10.003916 1031 | 1687.5 0.261868 10.017429 1032 | 1690.0 0.262418 10.030884 1033 | -------------------------------------------------------------------------------- /tmm_fast/materials/nSiO2.txt: -------------------------------------------------------------------------------- 1 | 300 1.492522717 6.23E-19 2 | 301 1.492243767 5.81E-19 3 | 302 1.491972923 5.43E-19 4 | 303 1.491684437 5.07E-19 5 | 304 1.491421103 4.74E-19 6 | 305 1.491155505 4.43E-19 7 | 306 1.490893126 4.14E-19 8 | 307 1.490635991 3.87E-19 9 | 308 1.490372181 3.62E-19 10 | 309 1.490136743 3.39E-19 11 | 310 1.489880443 3.18E-19 12 | 311 1.489638448 2.98E-19 13 | 312 1.489385366 2.79E-19 14 | 313 1.489142299 2.62E-19 15 | 314 1.488911748 2.46E-19 16 | 315 1.488669634 2.3E-19 17 | 316 1.488448858 2.16E-19 18 | 317 1.488211989 2.03E-19 19 | 318 1.488001704 1.91E-19 20 | 319 1.487800002 1.8E-19 21 | 320 1.487582445 1.69E-19 22 | 321 1.487342238 1.59E-19 23 | 322 1.487086535 1.49E-19 24 | 323 1.486857653 1.41E-19 25 | 324 1.486638665 1.33E-19 26 | 325 1.486410141 1.25E-19 27 | 326 1.486201406 1.18E-19 28 | 327 1.48597908 1.11E-19 29 | 328 1.485768318 1.05E-19 30 | 329 1.485570669 9.87E-20 31 | 330 1.485357761 9.32E-20 32 | 331 1.485157132 8.8E-20 33 | 332 1.484949946 8.31E-20 34 | 333 1.484738588 7.85E-20 35 | 334 1.484551907 7.42E-20 36 | 335 1.484352231 7.02E-20 37 | 336 1.484157324 6.64E-20 38 | 337 1.483972192 6.28E-20 39 | 338 1.483771324 5.94E-20 40 | 339 1.483590364 5.63E-20 41 | 340 1.48341608 5.33E-20 42 | 341 1.483228922 5.05E-20 43 | 342 1.483046889 4.78E-20 44 | 343 1.482859612 4.53E-20 45 | 344 1.482662916 4.3E-20 46 | 345 1.482493877 4.08E-20 47 | 346 1.482318163 3.87E-20 48 | 347 1.482136011 3.67E-20 49 | 348 1.481969833 3.48E-20 50 | 349 1.481795192 3.31E-20 51 | 350 1.481616497 3.14E-20 52 | 351 1.481461644 2.99E-20 53 | 352 1.481297493 2.84E-20 54 | 353 1.481127739 2.7E-20 55 | 354 1.480969548 2.57E-20 56 | 355 1.480802894 2.44E-20 57 | 356 1.480629325 2.32E-20 58 | 357 1.48048079 2.21E-20 59 | 358 1.480326176 2.1E-20 60 | 359 1.480163693 2E-20 61 | 360 1.480015159 1.91E-20 62 | 361 1.479864717 1.82E-20 63 | 362 1.479704261 1.73E-20 64 | 363 1.479563117 1.65E-20 65 | 364 1.479429126 1.58E-20 66 | 365 1.479281545 1.5E-20 67 | 366 1.47913444 1.43E-20 68 | 367 1.478987813 1.37E-20 69 | 368 1.478829145 1.31E-20 70 | 369 1.478672981 1.25E-20 71 | 370 1.478538752 1.19E-20 72 | 371 1.478397846 1.14E-20 73 | 372 1.478250384 1.09E-20 74 | 373 1.478115082 1.04E-20 75 | 374 1.477981329 9.93E-21 76 | 375 1.477835655 9.5E-21 77 | 376 1.477699399 9.08E-21 78 | 377 1.477576733 8.69E-21 79 | 378 1.47744453 8.31E-21 80 | 379 1.477308273 7.95E-21 81 | 380 1.477181554 7.62E-21 82 | 381 1.477053761 7.29E-21 83 | 382 1.476914287 6.99E-21 84 | 383 1.476783395 6.69E-21 85 | 384 1.476666093 6.41E-21 86 | 385 1.4765414 6.14E-21 87 | 386 1.4764117 5.89E-21 88 | 387 1.476292253 5.65E-21 89 | 388 1.476176262 5.41E-21 90 | 389 1.476048589 5.19E-21 91 | 390 1.475922585 4.98E-21 92 | 391 1.475816607 4.78E-21 93 | 392 1.475708008 4.59E-21 94 | 393 1.475589395 4.41E-21 95 | 394 1.475472689 4.23E-21 96 | 395 1.475358963 4.06E-21 97 | 396 1.475239873 3.9E-21 98 | 397 1.475114107 3.75E-21 99 | 398 1.474999666 3.6E-21 100 | 399 1.474895239 3.46E-21 101 | 400 1.474784255 3.33E-21 102 | 401 1.474668622 3.2E-21 103 | 402 1.474560738 3.08E-21 104 | 403 1.474457622 2.96E-21 105 | 404 1.474347115 2.85E-21 106 | 405 1.474232793 2.74E-21 107 | 406 1.474131107 2.64E-21 108 | 407 1.474036217 2.54E-21 109 | 408 1.473933578 2.44E-21 110 | 409 1.473827004 2.35E-21 111 | 410 1.473725677 2.27E-21 112 | 411 1.473628283 2.18E-21 113 | 412 1.473524451 2.1E-21 114 | 413 1.473415375 2.03E-21 115 | 414 1.473315001 1.95E-21 116 | 415 1.47322464 1.88E-21 117 | 416 1.473130584 1.82E-21 118 | 417 1.473029613 1.75E-21 119 | 418 1.472931981 1.69E-21 120 | 419 1.472842813 1.63E-21 121 | 420 1.472753048 1.57E-21 122 | 421 1.472653627 1.52E-21 123 | 422 1.472554445 1.46E-21 124 | 423 1.47247529 1.41E-21 125 | 424 1.472397804 1.36E-21 126 | 425 1.472311735 1.32E-21 127 | 426 1.472223282 1.27E-21 128 | 427 1.472132802 1.23E-21 129 | 428 1.472041011 1.19E-21 130 | 429 1.47194612 1.15E-21 131 | 430 1.471843719 1.11E-21 132 | 431 1.471742868 1.07E-21 133 | 432 1.471661091 1.04E-21 134 | 433 1.471579671 1E-21 135 | 434 1.471490502 9.69E-22 136 | 435 1.471399307 9.37E-22 137 | 436 1.471313357 9.06E-22 138 | 437 1.47123301 8.77E-22 139 | 438 1.47115159 8.48E-22 140 | 439 1.471061826 8.21E-22 141 | 440 1.470972419 7.95E-22 142 | 441 1.470895529 7.69E-22 143 | 442 1.470822215 7.45E-22 144 | 443 1.470745087 7.21E-22 145 | 444 1.470661759 6.99E-22 146 | 445 1.470578909 6.76E-22 147 | 446 1.470503211 6.56E-22 148 | 447 1.47042799 6.35E-22 149 | 448 1.470347047 6.15E-22 150 | 449 1.470261812 5.96E-22 151 | 450 1.470178604 5.78E-22 152 | 451 1.470108867 5.6E-22 153 | 452 1.470039487 5.43E-22 154 | 453 1.469964385 5.27E-22 155 | 454 1.469886065 5.11E-22 156 | 455 1.469808936 4.95E-22 157 | 456 1.469740033 4.81E-22 158 | 457 1.469671369 4.66E-22 159 | 458 1.469597697 4.52E-22 160 | 459 1.46952033 4.39E-22 161 | 460 1.469443202 4.26E-22 162 | 461 1.469381452 4.14E-22 163 | 462 1.469320059 4.01E-22 164 | 463 1.469254971 3.9E-22 165 | 464 1.469184518 3.79E-22 166 | 465 1.469114304 3.67E-22 167 | 466 1.469046354 3.57E-22 168 | 467 1.468979239 3.47E-22 169 | 468 1.46891129 3.37E-22 170 | 469 1.468835354 3.27E-22 171 | 470 1.468759775 3.18E-22 172 | 471 1.468690515 3.09E-22 173 | 472 1.468629837 3.01E-22 174 | 473 1.468569517 2.92E-22 175 | 474 1.468503118 2.84E-22 176 | 475 1.468434453 2.76E-22 177 | 476 1.468366027 2.68E-22 178 | 477 1.468305588 2.61E-22 179 | 478 1.468245864 2.54E-22 180 | 479 1.468184948 2.47E-22 181 | 480 1.468116999 2.4E-22 182 | 481 1.468049288 2.34E-22 183 | 482 1.467986465 2.28E-22 184 | 483 1.467932224 2.22E-22 185 | 484 1.467878103 2.16E-22 186 | 485 1.467819691 2.1E-22 187 | 486 1.467757106 2.04E-22 188 | 487 1.467694759 1.99E-22 189 | 488 1.467636228 1.94E-22 190 | 489 1.46758008 1.89E-22 191 | 490 1.467524171 1.84E-22 192 | 491 1.467462301 1.79E-22 193 | 492 1.467398047 1.74E-22 194 | 493 1.467334151 1.7E-22 195 | 494 1.467279553 1.66E-22 196 | 495 1.467228293 1.61E-22 197 | 496 1.467177272 1.57E-22 198 | 497 1.46712029 1.53E-22 199 | 498 1.467061758 1.49E-22 200 | 499 1.467003345 1.46E-22 201 | 500 1.466950536 1.42E-22 202 | 501 1.466899991 1.38E-22 203 | 502 1.466849566 1.35E-22 204 | 503 1.466794252 1.32E-22 205 | 504 1.466736674 1.28E-22 206 | 505 1.466679215 1.25E-22 207 | 506 1.466629386 1.22E-22 208 | 507 1.466585636 1.19E-22 209 | 508 1.466542006 1.16E-22 210 | 509 1.466495037 1.13E-22 211 | 510 1.466443777 1.11E-22 212 | 511 1.466392756 1.08E-22 213 | 512 1.466341734 1.05E-22 214 | 513 1.466290593 1.03E-22 215 | 514 1.466239691 1.01E-22 216 | 515 1.466188788 9.81E-23 217 | 516 1.466130614 9.59E-23 218 | 517 1.466072679 9.36E-23 219 | 518 1.466014862 9.14E-23 220 | 519 1.465967059 8.93E-23 221 | 520 1.465922236 8.72E-23 222 | 521 1.465877533 8.52E-23 223 | 522 1.465829611 8.32E-23 224 | 523 1.465777993 8.13E-23 225 | 524 1.465726733 7.95E-23 226 | 525 1.465676308 7.76E-23 227 | 526 1.465632081 7.59E-23 228 | 527 1.465587974 7.42E-23 229 | 528 1.465544105 7.25E-23 230 | 529 1.46549511 7.09E-23 231 | 530 1.465444565 6.93E-23 232 | 531 1.465394258 6.78E-23 233 | 532 1.46534729 6.62E-23 234 | 533 1.465307832 6.48E-23 235 | 534 1.465268373 6.34E-23 236 | 535 1.465229154 6.2E-23 237 | 536 1.465183854 6.06E-23 238 | 537 1.465137482 5.93E-23 239 | 538 1.465091467 5.8E-23 240 | 539 1.465047002 5.67E-23 241 | 540 1.465005755 5.55E-23 242 | 541 1.464964747 5.44E-23 243 | 542 1.464923859 5.32E-23 244 | 543 1.464877725 5.2E-23 245 | 544 1.464830041 5.1E-23 246 | 545 1.464782476 4.99E-23 247 | 546 1.464736462 4.88E-23 248 | 547 1.464699268 4.78E-23 249 | 548 1.464662075 4.68E-23 250 | 549 1.46462512 4.58E-23 251 | 550 1.464585185 4.48E-23 252 | 551 1.464541912 4.39E-23 253 | 552 1.464498758 4.3E-23 254 | 553 1.464455843 4.21E-23 255 | 554 1.464417458 4.13E-23 256 | 555 1.464380741 4.04E-23 257 | 556 1.464344263 3.96E-23 258 | 557 1.464307785 3.88E-23 259 | 558 1.464265227 3.8E-23 260 | 559 1.464222789 3.73E-23 261 | 560 1.46418047 3.65E-23 262 | 561 1.464140058 3.58E-23 263 | 562 1.46410799 3.51E-23 264 | 563 1.464076161 3.44E-23 265 | 564 1.464044333 3.37E-23 266 | 565 1.464010596 3.3E-23 267 | 566 1.463972569 3.24E-23 268 | 567 1.46393466 3.17E-23 269 | 568 1.46389699 3.11E-23 270 | 569 1.463860035 3.05E-23 271 | 570 1.463824153 2.99E-23 272 | 571 1.463788629 2.94E-23 273 | 572 1.463753104 2.88E-23 274 | 573 1.463715076 2.82E-23 275 | 574 1.463673472 2.77E-23 276 | 575 1.463631988 2.72E-23 277 | 576 1.463590741 2.66E-23 278 | 577 1.46355319 2.61E-23 279 | 578 1.463521719 2.57E-23 280 | 579 1.463490367 2.52E-23 281 | 580 1.463459015 2.47E-23 282 | 581 1.463426232 2.42E-23 283 | 582 1.463389277 2.38E-23 284 | 583 1.463352561 2.33E-23 285 | 584 1.463315964 2.29E-23 286 | 585 1.463280201 2.25E-23 287 | 586 1.463249087 2.21E-23 288 | 587 1.463218093 2.17E-23 289 | 588 1.463187218 2.13E-23 290 | 589 1.463156343 2.09E-23 291 | 590 1.463120461 2.05E-23 292 | 591 1.463084221 2.01E-23 293 | 592 1.4630481 1.98E-23 294 | 593 1.463012218 1.94E-23 295 | 594 1.462981939 1.91E-23 296 | 595 1.46295464 1.87E-23 297 | 596 1.462927341 1.84E-23 298 | 597 1.462900043 1.81E-23 299 | 598 1.462871075 1.78E-23 300 | 599 1.462838173 1.74E-23 301 | 600 1.46280551 1.71E-23 302 | 601 1.462772846 1.68E-23 303 | 602 1.462740302 1.65E-23 304 | 603 1.462711453 1.63E-23 305 | 604 1.462682724 1.6E-23 306 | 605 1.462654233 1.57E-23 307 | 606 1.462625742 1.54E-23 308 | 607 1.462594748 1.52E-23 309 | 608 1.462560773 1.49E-23 310 | 609 1.462527037 1.47E-23 311 | 610 1.46249342 1.44E-23 312 | 611 1.462459803 1.42E-23 313 | 612 1.462433934 1.39E-23 314 | 613 1.462408543 1.37E-23 315 | 614 1.462383151 1.35E-23 316 | 615 1.462357998 1.32E-23 317 | 616 1.462330937 1.3E-23 318 | 617 1.462300777 1.28E-23 319 | 618 1.462270737 1.26E-23 320 | 619 1.462240815 1.24E-23 321 | 620 1.462210894 1.22E-23 322 | 621 1.462184548 1.2E-23 323 | 622 1.462159634 1.18E-23 324 | 623 1.462134957 1.16E-23 325 | 624 1.462110281 1.14E-23 326 | 625 1.462085605 1.12E-23 327 | 626 1.462056398 1.1E-23 328 | 627 1.462027192 1.09E-23 329 | 628 1.461997867 1.07E-23 330 | 629 1.46196878 1.05E-23 331 | 630 1.461941242 1.03E-23 332 | 631 1.461921692 1.02E-23 333 | 632 1.461902261 1E-23 334 | 633 1.461882949 9.86E-24 335 | 634 1.461863637 9.7E-24 336 | 635 1.461843014 9.55E-24 337 | 636 1.461818695 9.4E-24 338 | 637 1.461794376 9.26E-24 339 | 638 1.461770296 9.11E-24 340 | 639 1.461746216 8.97E-24 341 | 640 1.461721063 8.83E-24 342 | 641 1.461693764 8.7E-24 343 | 642 1.461666346 8.56E-24 344 | 643 1.461639166 8.43E-24 345 | 644 1.461611986 8.3E-24 346 | 645 1.461583614 8.17E-24 347 | 646 1.461551785 8.05E-24 348 | 647 1.461520076 7.93E-24 349 | 648 1.461488485 7.81E-24 350 | 649 1.461456895 7.69E-24 351 | 650 1.461426854 7.57E-24 352 | 651 1.461404443 7.46E-24 353 | 652 1.461382151 7.36E-24 354 | 653 1.461359859 7.25E-24 355 | 654 1.461337686 7.14E-24 356 | 655 1.461315632 7.03E-24 357 | 656 1.461289167 6.93E-24 358 | 657 1.461262584 6.83E-24 359 | 658 1.461236238 6.73E-24 360 | 659 1.461209893 6.63E-24 361 | 660 1.461183548 6.53E-24 362 | 661 1.461160302 6.44E-24 363 | 662 1.461138606 6.34E-24 364 | 663 1.46111691 6.25E-24 365 | 664 1.461095333 6.16E-24 366 | 665 1.461073756 6.07E-24 367 | 666 1.461050868 5.99E-24 368 | 667 1.461025 5.9E-24 369 | 668 1.46099925 5.82E-24 370 | 669 1.46097362 5.74E-24 371 | 670 1.46094799 5.65E-24 372 | 671 1.46092236 5.57E-24 373 | 672 1.460902572 5.5E-24 374 | 673 1.460883856 5.42E-24 375 | 674 1.46086514 5.35E-24 376 | 675 1.460846543 5.27E-24 377 | 676 1.460827947 5.2E-24 378 | 677 1.46080792 5.12E-24 379 | 678 1.460784912 5.05E-24 380 | 679 1.460761905 4.99E-24 381 | 680 1.460739017 4.92E-24 382 | 681 1.460716009 4.85E-24 383 | 682 1.46069324 4.78E-24 384 | 683 1.460672498 4.72E-24 385 | 684 1.46065259 4.65E-24 386 | 685 1.460632801 4.59E-24 387 | 686 1.460613132 4.53E-24 388 | 687 1.460593462 4.47E-24 389 | 688 1.460573912 4.41E-24 390 | 689 1.460550308 4.35E-24 391 | 690 1.460526466 4.29E-24 392 | 691 1.460502625 4.23E-24 393 | 692 1.460479021 4.18E-24 394 | 693 1.460455418 4.12E-24 395 | 694 1.460432529 4.07E-24 396 | 695 1.460415125 4.01E-24 397 | 696 1.46039772 3.96E-24 398 | 697 1.460380316 3.91E-24 399 | 698 1.46036303 3.86E-24 400 | 699 1.460345745 3.81E-24 401 | 700 1.460327864 3.76E-24 402 | 701 1.460306883 3.71E-24 403 | 702 1.460285902 3.66E-24 404 | 703 1.460264921 3.62E-24 405 | 704 1.46024406 3.57E-24 406 | 705 1.460223198 3.52E-24 407 | 706 1.460202932 3.48E-24 408 | 707 1.460185766 3.43E-24 409 | 708 1.4601686 3.39E-24 410 | 709 1.460151553 3.35E-24 411 | 710 1.460134625 3.31E-24 412 | 711 1.460117579 3.26E-24 413 | 712 1.46010077 3.22E-24 414 | 713 1.460080028 3.18E-24 415 | 714 1.460059404 3.14E-24 416 | 715 1.460038781 3.11E-24 417 | 716 1.460018396 3.07E-24 418 | 717 1.459997892 3.03E-24 419 | 718 1.459977388 2.99E-24 420 | 719 1.459961653 2.95E-24 421 | 720 1.459947348 2.92E-24 422 | 721 1.459933162 2.88E-24 423 | 722 1.459918976 2.85E-24 424 | 723 1.45990479 2.81E-24 425 | 724 1.459890723 2.78E-24 426 | 725 1.459875107 2.74E-24 427 | 726 1.459857225 2.71E-24 428 | 727 1.459839463 2.68E-24 429 | 728 1.459821582 2.65E-24 430 | 729 1.459803939 2.62E-24 431 | 730 1.459786177 2.58E-24 432 | 731 1.459768534 2.55E-24 433 | 732 1.459751844 2.52E-24 434 | 733 1.459735274 2.49E-24 435 | 734 1.459718704 2.46E-24 436 | 735 1.459702253 2.43E-24 437 | 736 1.459685802 2.41E-24 438 | 737 1.459669352 2.38E-24 439 | 738 1.459651709 2.35E-24 440 | 739 1.459631681 2.32E-24 441 | 740 1.459611773 2.3E-24 442 | 741 1.459591866 2.27E-24 443 | 742 1.459571958 2.24E-24 444 | 743 1.459552169 2.22E-24 445 | 744 1.459532499 2.19E-24 446 | 745 1.459516406 2.17E-24 447 | 746 1.459502339 2.14E-24 448 | 747 1.459488392 2.12E-24 449 | 748 1.459474325 2.09E-24 450 | 749 1.459460378 2.07E-24 451 | 750 1.459446549 2.05E-24 452 | 751 1.459432721 2.02E-24 453 | 752 1.459416151 2E-24 454 | 753 1.459398866 1.98E-24 455 | 754 1.4593817 1.96E-24 456 | 755 1.459364533 1.93E-24 457 | 756 1.459347486 1.91E-24 458 | 757 1.459330559 1.89E-24 459 | 758 1.459313512 1.87E-24 460 | 759 1.459299207 1.85E-24 461 | 760 1.459285378 1.83E-24 462 | 761 1.459271669 1.81E-24 463 | 762 1.45925796 1.79E-24 464 | 763 1.459244132 1.77E-24 465 | 764 1.459230542 1.75E-24 466 | 765 1.459216952 1.73E-24 467 | 766 1.45920074 1.71E-24 468 | 767 1.459183931 1.69E-24 469 | 768 1.459167004 1.67E-24 470 | 769 1.459150195 1.66E-24 471 | 770 1.459133506 1.64E-24 472 | 771 1.459116817 1.62E-24 473 | 772 1.459100127 1.6E-24 474 | 773 1.459086299 1.59E-24 475 | 774 1.459074497 1.57E-24 476 | 775 1.459062934 1.55E-24 477 | 776 1.459051251 1.54E-24 478 | 777 1.459039569 1.52E-24 479 | 778 1.459028006 1.5E-24 480 | 779 1.459016442 1.49E-24 481 | 780 1.459004283 1.47E-24 482 | 781 1.458989382 1.46E-24 483 | 782 1.4589746 1.44E-24 484 | 783 1.458959699 1.43E-24 485 | 784 1.458944917 1.41E-24 486 | 785 1.458930254 1.4E-24 487 | 786 1.458915472 1.38E-24 488 | 787 1.458900809 1.37E-24 489 | 788 1.458887577 1.35E-24 490 | 789 1.458875179 1.34E-24 491 | 790 1.458862662 1.33E-24 492 | 791 1.458850265 1.31E-24 493 | 792 1.458837986 1.3E-24 494 | 793 1.458825588 1.29E-24 495 | 794 1.45881331 1.27E-24 496 | 795 1.458800793 1.26E-24 497 | 796 1.458785295 1.25E-24 498 | 797 1.458769798 1.24E-24 499 | 798 1.458754301 1.22E-24 500 | 799 1.458738804 1.21E-24 501 | 800 1.458723426 1.2E-24 502 | 801 1.458708048 1.19E-24 503 | 802 1.458692789 1.18E-24 504 | 803 1.458678603 1.16E-24 505 | 804 1.458667874 1.15E-24 506 | 805 1.458657146 1.14E-24 507 | 806 1.458646536 1.13E-24 508 | 807 1.458635807 1.12E-24 509 | 808 1.458625197 1.11E-24 510 | 809 1.458614707 1.1E-24 511 | 810 1.458604097 1.09E-24 512 | 811 1.458592653 1.08E-24 513 | 812 1.458579183 1.07E-24 514 | 813 1.458565712 1.06E-24 515 | 814 1.458552361 1.05E-24 516 | 815 1.45853889 1.04E-24 517 | 816 1.458525658 1.03E-24 518 | 817 1.458512306 1.02E-24 519 | 818 1.458499074 1.01E-24 520 | 819 1.458486319 9.95E-25 521 | 820 1.458475828 9.86E-25 522 | 821 1.458465338 9.77E-25 523 | 822 1.458454847 9.68E-25 524 | 823 1.458444476 9.59E-25 525 | 824 1.458434105 9.5E-25 526 | 825 1.458423734 9.41E-25 527 | 826 1.458413363 9.32E-25 528 | 827 1.458402991 9.23E-25 529 | 828 1.458390117 9.14E-25 530 | 829 1.458377004 9.06E-25 531 | 830 1.458363891 8.98E-25 532 | 831 1.458350897 8.9E-25 533 | 832 1.458337903 8.81E-25 534 | 833 1.458324909 8.73E-25 535 | 834 1.458312035 8.65E-25 536 | 835 1.45829916 8.57E-25 537 | 836 1.45828855 8.49E-25 538 | 837 1.458280444 8.41E-25 539 | 838 1.458272338 8.34E-25 540 | 839 1.458264232 8.26E-25 541 | 840 1.458256245 8.19E-25 542 | 841 1.458248138 8.11E-25 543 | 842 1.458240151 8.04E-25 544 | 843 1.458232164 7.97E-25 545 | 844 1.458224177 7.89E-25 546 | 845 1.458213806 7.82E-25 547 | 846 1.458202958 7.76E-25 548 | 847 1.458192229 7.69E-25 549 | 848 1.4581815 7.62E-25 550 | 849 1.458170891 7.55E-25 551 | 850 1.458160162 7.48E-25 552 | 851 1.458149552 7.42E-25 553 | 852 1.458138943 7.35E-25 554 | 853 1.458128333 7.28E-25 555 | 854 1.458117485 7.22E-25 556 | 855 1.458106875 7.16E-25 557 | 856 1.458096147 7.1E-25 558 | 857 1.458085537 7.04E-25 559 | 858 1.458074808 6.98E-25 560 | 859 1.458064198 6.91E-25 561 | 860 1.45805347 6.85E-25 562 | 861 1.458042979 6.79E-25 563 | 862 1.458032131 6.73E-25 564 | 863 1.458018899 6.68E-25 565 | 864 1.458005667 6.62E-25 566 | 865 1.457992554 6.57E-25 567 | 866 1.457979321 6.51E-25 568 | 867 1.457966208 6.45E-25 569 | 868 1.457953095 6.4E-25 570 | 869 1.457940102 6.34E-25 571 | 870 1.457926989 6.29E-25 572 | 871 1.457913995 6.23E-25 573 | 872 1.457905173 6.18E-25 574 | 873 1.457896471 6.13E-25 575 | 874 1.457887888 6.08E-25 576 | 875 1.457879305 6.03E-25 577 | 876 1.457870841 5.98E-25 578 | 877 1.457862258 5.93E-25 579 | 878 1.457853794 5.88E-25 580 | 879 1.45784533 5.83E-25 581 | 880 1.457836866 5.78E-25 582 | 881 1.457826972 5.73E-25 583 | 882 1.457816124 5.69E-25 584 | 883 1.457805157 5.64E-25 585 | 884 1.457794309 5.6E-25 586 | 885 1.45778358 5.55E-25 587 | 886 1.457772613 5.51E-25 588 | 887 1.457761884 5.46E-25 589 | 888 1.457751155 5.42E-25 590 | 889 1.457740426 5.37E-25 591 | 890 1.457729578 5.33E-25 592 | 891 1.457721233 5.28E-25 593 | 892 1.457712889 5.24E-25 594 | 893 1.457704544 5.2E-25 595 | 894 1.457696199 5.16E-25 596 | 895 1.457687855 5.12E-25 597 | 896 1.457679629 5.08E-25 598 | 897 1.457671285 5.04E-25 599 | 898 1.45766294 5E-25 600 | 899 1.457654834 4.95E-25 601 | 900 1.457646012 4.91E-25 602 | 901 1.457635283 4.88E-25 603 | 902 1.457624793 4.84E-25 604 | 903 1.457614183 4.8E-25 605 | 904 1.457603574 4.77E-25 606 | 905 1.457593083 4.73E-25 607 | 906 1.457582593 4.69E-25 608 | 907 1.457571983 4.65E-25 609 | 908 1.457561612 4.62E-25 610 | 909 1.457551241 4.58E-25 611 | 910 1.457541585 4.54E-25 612 | 911 1.457534671 4.51E-25 613 | 912 1.457527757 4.48E-25 614 | 913 1.457520962 4.44E-25 615 | 914 1.457514048 4.41E-25 616 | 915 1.457507133 4.37E-25 617 | 916 1.457500339 4.34E-25 618 | 917 1.457493663 4.31E-25 619 | 918 1.457486868 4.27E-25 620 | 919 1.457480073 4.24E-25 621 | 920 1.457473278 4.21E-25 622 | 921 1.457464099 4.18E-25 623 | 922 1.457455039 4.15E-25 624 | 923 1.45744586 4.12E-25 625 | 924 1.4574368 4.08E-25 626 | 925 1.457427621 4.05E-25 627 | 926 1.457418561 4.02E-25 628 | 927 1.457409501 3.99E-25 629 | 928 1.45740056 3.96E-25 630 | 929 1.4573915 3.93E-25 631 | 930 1.45738256 3.9E-25 632 | 931 1.457374334 3.87E-25 633 | 932 1.457366943 3.85E-25 634 | 933 1.457359433 3.82E-25 635 | 934 1.457352042 3.79E-25 636 | 935 1.457344651 3.76E-25 637 | 936 1.45733726 3.74E-25 638 | 937 1.457329869 3.71E-25 639 | 938 1.457322478 3.68E-25 640 | 939 1.457315087 3.65E-25 641 | 940 1.457307816 3.63E-25 642 | 941 1.457300425 3.6E-25 643 | 942 1.457291245 3.57E-25 644 | 943 1.45728159 3.55E-25 645 | 944 1.457272053 3.52E-25 646 | 945 1.457262397 3.5E-25 647 | 946 1.45725286 3.47E-25 648 | 947 1.457243323 3.45E-25 649 | 948 1.457233787 3.42E-25 650 | 949 1.457224369 3.4E-25 651 | 950 1.457214832 3.37E-25 652 | 951 1.457205296 3.35E-25 653 | 952 1.457195878 3.33E-25 654 | 953 1.457189441 3.3E-25 655 | 954 1.457183242 3.28E-25 656 | 955 1.457177043 3.26E-25 657 | 956 1.457170963 3.23E-25 658 | 957 1.457164764 3.21E-25 659 | 958 1.457158685 3.19E-25 660 | 959 1.457152486 3.17E-25 661 | 960 1.457146406 3.15E-25 662 | 961 1.457140207 3.12E-25 663 | 962 1.457134128 3.1E-25 664 | 963 1.457128167 3.08E-25 665 | 964 1.457120538 3.06E-25 666 | 965 1.457112432 3.04E-25 667 | 966 1.457104325 3.02E-25 668 | 967 1.457096219 3E-25 669 | 968 1.457088113 2.98E-25 670 | 969 1.457080007 2.96E-25 671 | 970 1.4570719 2.94E-25 672 | 971 1.457063913 2.92E-25 673 | 972 1.457055926 2.89E-25 674 | 973 1.45704782 2.87E-25 675 | 974 1.457039833 2.85E-25 676 | 975 1.457032323 2.83E-25 677 | 976 1.457026124 2.82E-25 678 | 977 1.457020164 2.8E-25 679 | 978 1.457013965 2.78E-25 680 | 979 1.457007885 2.76E-25 681 | 980 1.457001925 2.74E-25 682 | 981 1.456995845 2.72E-25 683 | 982 1.456989765 2.71E-25 684 | 983 1.456983805 2.69E-25 685 | 984 1.456977725 2.67E-25 686 | 985 1.456971765 2.65E-25 687 | 986 1.456965804 2.63E-25 688 | 987 1.456958771 2.62E-25 689 | 988 1.456950784 2.6E-25 690 | 989 1.456942916 2.58E-25 691 | 990 1.456935048 2.57E-25 692 | 991 1.456927061 2.55E-25 693 | 992 1.456919193 2.53E-25 694 | 993 1.456911325 2.52E-25 695 | 994 1.456903577 2.5E-25 696 | 995 1.456895709 2.48E-25 697 | 996 1.456887841 2.47E-25 698 | 997 1.456880093 2.45E-25 699 | 998 1.456872225 2.43E-25 700 | 999 1.456866026 2.42E-25 701 | 1000 1.456861258 2.4E-25 702 | 1001 1.456856608 2.39E-25 703 | 1002 1.456851959 2.37E-25 704 | 1003 1.456847429 2.36E-25 705 | 1004 1.45684278 2.34E-25 706 | 1005 1.456838131 2.33E-25 707 | 1006 1.456833482 2.31E-25 708 | 1007 1.456828952 2.3E-25 709 | 1008 1.456824303 2.28E-25 710 | 1009 1.456819773 2.27E-25 711 | 1010 1.456815124 2.25E-25 712 | 1011 1.456810355 2.24E-25 713 | 1012 1.456803799 2.23E-25 714 | 1013 1.456797361 2.21E-25 715 | 1014 1.456790805 2.2E-25 716 | 1015 1.456784248 2.19E-25 717 | 1016 1.456777811 2.17E-25 718 | 1017 1.456771374 2.16E-25 719 | 1018 1.456764936 2.15E-25 720 | 1019 1.456758499 2.13E-25 721 | 1020 1.456752062 2.12E-25 722 | 1021 1.456745625 2.11E-25 723 | 1022 1.456739306 2.09E-25 724 | 1023 1.456732869 2.08E-25 725 | 1024 1.456726789 2.07E-25 726 | 1025 1.456720829 2.05E-25 727 | 1026 1.456715107 2.04E-25 728 | 1027 1.456709146 2.03E-25 729 | 1028 1.456703424 2.02E-25 730 | 1029 1.456697583 2E-25 731 | 1030 1.456691861 1.99E-25 732 | 1031 1.45668602 1.98E-25 733 | 1032 1.456680179 1.97E-25 734 | 1033 1.456674457 1.96E-25 735 | 1034 1.456668735 1.94E-25 736 | 1035 1.456662893 1.93E-25 737 | 1036 1.456657171 1.92E-25 738 | 1037 1.456650496 1.91E-25 739 | 1038 1.456642985 1.9E-25 740 | 1039 1.456635356 1.89E-25 741 | 1040 1.456627846 1.88E-25 742 | 1041 1.456620336 1.86E-25 743 | 1042 1.456612825 1.85E-25 744 | 1043 1.456605196 1.84E-25 745 | 1044 1.456597805 1.83E-25 746 | 1045 1.456590414 1.82E-25 747 | 1046 1.456582904 1.81E-25 748 | 1047 1.456575513 1.8E-25 749 | 1048 1.456568003 1.79E-25 750 | 1049 1.456560612 1.78E-25 751 | 1050 1.456553936 1.77E-25 752 | 1051 1.456549287 1.76E-25 753 | 1052 1.456544638 1.75E-25 754 | 1053 1.456539989 1.74E-25 755 | 1054 1.456535459 1.73E-25 756 | 1055 1.456530809 1.72E-25 757 | 1056 1.456526279 1.71E-25 758 | 1057 1.456521749 1.7E-25 759 | 1058 1.45651722 1.69E-25 760 | 1059 1.45651257 1.68E-25 761 | 1060 1.45650816 1.67E-25 762 | 1061 1.45650351 1.66E-25 763 | 1062 1.456498981 1.65E-25 764 | 1063 1.45649457 1.64E-25 765 | 1064 1.456488967 1.63E-25 766 | 1065 1.456482768 1.62E-25 767 | 1066 1.456476569 1.61E-25 768 | 1067 1.45647049 1.6E-25 769 | 1068 1.456464291 1.59E-25 770 | 1069 1.456458211 1.59E-25 771 | 1070 1.456452131 1.58E-25 772 | 1071 1.456445932 1.57E-25 773 | 1072 1.456439972 1.56E-25 774 | 1073 1.456433773 1.55E-25 775 | 1074 1.456427693 1.54E-25 776 | 1075 1.456421614 1.53E-25 777 | 1076 1.456415653 1.52E-25 778 | 1077 1.456409693 1.51E-25 779 | 1078 1.456404567 1.51E-25 780 | 1079 1.456400037 1.5E-25 781 | 1080 1.456395507 1.49E-25 782 | 1081 1.456390977 1.48E-25 783 | 1082 1.456386447 1.47E-25 784 | 1083 1.456381917 1.47E-25 785 | 1084 1.456377506 1.46E-25 786 | 1085 1.456373096 1.45E-25 787 | 1086 1.456368685 1.44E-25 788 | 1087 1.456364155 1.43E-25 789 | 1088 1.456359744 1.43E-25 790 | 1089 1.456355333 1.42E-25 791 | 1090 1.456350923 1.41E-25 792 | 1091 1.456346393 1.4E-25 793 | 1092 1.456341505 1.39E-25 794 | 1093 1.456335545 1.39E-25 795 | 1094 1.456329465 1.38E-25 796 | 1095 1.456323504 1.37E-25 797 | 1096 1.456317544 1.37E-25 798 | 1097 1.456311584 1.36E-25 799 | 1098 1.456305623 1.35E-25 800 | 1099 1.456299663 1.34E-25 801 | 1100 1.456293702 1.34E-25 802 | 1101 1.456287861 1.33E-25 803 | 1102 1.4562819 1.32E-25 804 | 1103 1.45627594 1.32E-25 805 | 1104 1.456270099 1.31E-25 806 | 1105 1.456264138 1.3E-25 807 | 1106 1.456258297 1.29E-25 808 | 1107 1.456253648 1.29E-25 809 | 1108 1.456250191 1.28E-25 810 | 1109 1.456246614 1.27E-25 811 | 1110 1.456243277 1.27E-25 812 | 1111 1.4562397 1.26E-25 813 | 1112 1.456236243 1.25E-25 814 | 1113 1.456232786 1.25E-25 815 | 1114 1.456229329 1.24E-25 816 | 1115 1.456225872 1.24E-25 817 | 1116 1.456222415 1.23E-25 818 | 1117 1.456218958 1.22E-25 819 | 1118 1.456215501 1.22E-25 820 | 1119 1.456212163 1.21E-25 821 | 1120 1.456208706 1.2E-25 822 | 1121 1.456205368 1.2E-25 823 | 1122 1.456201315 1.19E-25 824 | 1123 1.456196308 1.18E-25 825 | 1124 1.456191301 1.18E-25 826 | 1125 1.456186295 1.17E-25 827 | 1126 1.456181288 1.17E-25 828 | 1127 1.456176281 1.16E-25 829 | 1128 1.456171393 1.16E-25 830 | 1129 1.456166387 1.15E-25 831 | 1130 1.45616138 1.14E-25 832 | 1131 1.456156492 1.14E-25 833 | 1132 1.456151485 1.13E-25 834 | 1133 1.456146598 1.13E-25 835 | 1134 1.456141591 1.12E-25 836 | 1135 1.456136703 1.12E-25 837 | 1136 1.456131816 1.11E-25 838 | 1137 1.456126928 1.1E-25 839 | 1138 1.456122756 1.1E-25 840 | 1139 1.456118941 1.09E-25 841 | 1140 1.456115127 1.09E-25 842 | 1141 1.456111193 1.08E-25 843 | 1142 1.456107378 1.08E-25 844 | 1143 1.456103444 1.07E-25 845 | 1144 1.456099629 1.07E-25 846 | 1145 1.456095815 1.06E-25 847 | 1146 1.456092 1.06E-25 848 | 1147 1.456088185 1.05E-25 849 | 1148 1.456084371 1.05E-25 850 | 1149 1.456080556 1.04E-25 851 | 1150 1.456076741 1.04E-25 852 | 1151 1.456072927 1.03E-25 853 | 1152 1.456069231 1.02E-25 854 | 1153 1.456065416 1.02E-25 855 | 1154 1.45606041 1.01E-25 856 | 1155 1.456055045 1.01E-25 857 | 1156 1.456049681 1.01E-25 858 | 1157 1.456044316 1E-25 859 | 1158 1.456039071 9.96E-26 860 | 1159 1.456033707 9.91E-26 861 | 1160 1.456028461 9.86E-26 862 | 1161 1.456023216 9.82E-26 863 | 1162 1.456017852 9.77E-26 864 | 1163 1.456012487 9.72E-26 865 | 1164 1.456007242 9.68E-26 866 | 1165 1.456001997 9.63E-26 867 | 1166 1.455996752 9.58E-26 868 | 1167 1.455991507 9.54E-26 869 | 1168 1.455986381 9.49E-26 870 | 1169 1.455981135 9.44E-26 871 | 1170 1.455976486 9.4E-26 872 | 1171 1.455973506 9.36E-26 873 | 1172 1.455970407 9.31E-26 874 | 1173 1.455967426 9.27E-26 875 | 1174 1.455964327 9.23E-26 876 | 1175 1.455961347 9.19E-26 877 | 1176 1.455958366 9.14E-26 878 | 1177 1.455955386 9.1E-26 879 | 1178 1.455952287 9.06E-26 880 | 1179 1.455949426 9.02E-26 881 | 1180 1.455946326 8.97E-26 882 | 1181 1.455943465 8.93E-26 883 | 1182 1.455940366 8.89E-26 884 | 1183 1.455937386 8.85E-26 885 | 1184 1.455934525 8.81E-26 886 | 1185 1.455931544 8.76E-26 887 | 1186 1.455928564 8.72E-26 888 | 1187 1.455925107 8.68E-26 889 | 1188 1.455920815 8.64E-26 890 | 1189 1.455916524 8.61E-26 891 | 1190 1.455912232 8.57E-26 892 | 1191 1.455907941 8.53E-26 893 | 1192 1.455903649 8.49E-26 894 | 1193 1.455899239 8.45E-26 895 | 1194 1.455895066 8.42E-26 896 | 1195 1.455890775 8.38E-26 897 | 1196 1.455886483 8.34E-26 898 | 1197 1.455882311 8.3E-26 899 | 1198 1.455878019 8.26E-26 900 | 1199 1.455873728 8.23E-26 901 | 1200 1.455869436 8.19E-26 902 | 1201 1.455865264 8.15E-26 903 | 1202 1.455861092 8.11E-26 904 | 1203 1.4558568 8.08E-26 905 | 1204 1.455852628 8.04E-26 906 | 1205 1.455849528 8E-26 907 | 1206 1.455846548 7.97E-26 908 | 1207 1.455843568 7.93E-26 909 | 1208 1.455840588 7.9E-26 910 | 1209 1.455837607 7.87E-26 911 | 1210 1.455834627 7.83E-26 912 | 1211 1.455831766 7.8E-26 913 | 1212 1.455828786 7.76E-26 914 | 1213 1.455825806 7.73E-26 915 | 1214 1.455822945 7.7E-26 916 | 1215 1.455820084 7.66E-26 917 | 1216 1.455817103 7.63E-26 918 | 1217 1.455814123 7.59E-26 919 | 1218 1.455811262 7.56E-26 920 | 1219 1.455808282 7.53E-26 921 | 1220 1.455805421 7.49E-26 922 | 1221 1.45580256 7.46E-26 923 | 1222 1.45579958 7.43E-26 924 | 1223 1.455795646 7.39E-26 925 | 1224 1.455791473 7.36E-26 926 | 1225 1.455787301 7.33E-26 927 | 1226 1.455783129 7.3E-26 928 | 1227 1.455779076 7.27E-26 929 | 1228 1.455775023 7.24E-26 930 | 1229 1.45577085 7.21E-26 931 | 1230 1.455766797 7.18E-26 932 | 1231 1.455762744 7.15E-26 933 | 1232 1.455758572 7.12E-26 934 | 1233 1.455754519 7.09E-26 935 | 1234 1.455750465 7.06E-26 936 | 1235 1.455746293 7.03E-26 937 | 1236 1.455742359 7E-26 938 | 1237 1.455738187 6.97E-26 939 | 1238 1.455734253 6.94E-26 940 | 1239 1.4557302 6.91E-26 941 | 1240 1.455726147 6.88E-26 942 | 1241 1.455723047 6.85E-26 943 | 1242 1.455721259 6.82E-26 944 | 1243 1.45571959 6.79E-26 945 | 1244 1.455717802 6.76E-26 946 | 1245 1.455716014 6.74E-26 947 | 1246 1.455714345 6.71E-26 948 | 1247 1.455712557 6.68E-26 949 | 1248 1.455710888 6.65E-26 950 | 1249 1.4557091 6.63E-26 951 | 1250 1.455707431 6.6E-26 952 | 1251 1.455705762 6.57E-26 953 | 1252 1.455703974 6.54E-26 954 | 1253 1.455702305 6.52E-26 955 | 1254 1.455700517 6.49E-26 956 | 1255 1.455698848 6.46E-26 957 | 1256 1.455697179 6.44E-26 958 | 1257 1.45569551 6.41E-26 959 | 1258 1.455693722 6.38E-26 960 | 1259 1.455692053 6.35E-26 961 | 1260 1.455690026 6.33E-26 962 | 1261 1.455687046 6.3E-26 963 | 1262 1.455684066 6.28E-26 964 | 1263 1.455681086 6.25E-26 965 | 1264 1.455678105 6.23E-26 966 | 1265 1.455675125 6.2E-26 967 | 1266 1.455672264 6.18E-26 968 | 1267 1.455669284 6.15E-26 969 | 1268 1.455666304 6.13E-26 970 | 1269 1.455663323 6.11E-26 971 | 1270 1.455660462 6.08E-26 972 | 1271 1.455657601 6.06E-26 973 | 1272 1.455654621 6.03E-26 974 | 1273 1.45565176 6.01E-26 975 | 1274 1.45564878 5.98E-26 976 | 1275 1.455645919 5.96E-26 977 | 1276 1.455642939 5.93E-26 978 | 1277 1.455640078 5.91E-26 979 | 1278 1.455637217 5.89E-26 980 | 1279 1.455634356 5.86E-26 981 | 1280 1.455631137 5.84E-26 982 | 1281 1.455627799 5.82E-26 983 | 1282 1.455624461 5.79E-26 984 | 1283 1.455621123 5.77E-26 985 | 1284 1.455617785 5.75E-26 986 | 1285 1.455614448 5.73E-26 987 | 1286 1.45561111 5.71E-26 988 | 1287 1.455607772 5.68E-26 989 | 1288 1.455604434 5.66E-26 990 | 1289 1.455601096 5.64E-26 991 | 1290 1.455597878 5.62E-26 992 | 1291 1.45559454 5.6E-26 993 | 1292 1.455591202 5.57E-26 994 | 1293 1.455587983 5.55E-26 995 | 1294 1.455584645 5.53E-26 996 | 1295 1.455581427 5.51E-26 997 | 1296 1.455578089 5.49E-26 998 | 1297 1.45557487 5.47E-26 999 | 1298 1.455571532 5.44E-26 1000 | 1299 1.455568314 5.42E-26 1001 | 1300 1.455564737 5.4E-26 1002 | 1301 1.455560207 5.38E-26 1003 | 1302 1.455555797 5.36E-26 1004 | 1303 1.455551386 5.34E-26 1005 | 1304 1.455546856 5.32E-26 1006 | 1305 1.455542445 5.3E-26 1007 | 1306 1.455538034 5.28E-26 1008 | 1307 1.455533624 5.26E-26 1009 | 1308 1.455529332 5.24E-26 1010 | 1309 1.455524921 5.22E-26 1011 | 1310 1.455520511 5.2E-26 1012 | 1311 1.4555161 5.18E-26 1013 | 1312 1.455511689 5.16E-26 1014 | 1313 1.455507398 5.14E-26 1015 | 1314 1.455502987 5.12E-26 1016 | 1315 1.455498695 5.11E-26 1017 | 1316 1.455494285 5.09E-26 1018 | 1317 1.455489993 5.07E-26 1019 | 1318 1.455485702 5.05E-26 1020 | 1319 1.455481291 5.03E-26 1021 | 1320 1.455476999 5.01E-26 1022 | 1321 1.455473423 4.99E-26 1023 | 1322 1.455471039 4.97E-26 1024 | 1323 1.455468774 4.95E-26 1025 | 1324 1.455466509 4.94E-26 1026 | 1325 1.455464244 4.92E-26 1027 | 1326 1.455461979 4.9E-26 1028 | 1327 1.455459714 4.88E-26 1029 | 1328 1.455457449 4.86E-26 1030 | 1329 1.455455065 4.85E-26 1031 | 1330 1.455452919 4.83E-26 1032 | 1331 1.455450654 4.81E-26 1033 | 1332 1.45544827 4.79E-26 1034 | 1333 1.455446124 4.78E-26 1035 | 1334 1.45544374 4.76E-26 1036 | 1335 1.455441594 4.74E-26 1037 | 1336 1.455439329 4.72E-26 1038 | 1337 1.455437064 4.71E-26 1039 | 1338 1.455434918 4.69E-26 1040 | 1339 1.455432653 4.67E-26 1041 | 1340 1.455430388 4.65E-26 1042 | 1341 1.455428123 4.64E-26 1043 | 1342 1.455425978 4.62E-26 1044 | 1343 1.455422997 4.6E-26 1045 | 1344 1.45541966 4.59E-26 1046 | 1345 1.455416441 4.57E-26 1047 | 1346 1.455413222 4.56E-26 1048 | 1347 1.455410004 4.54E-26 1049 | 1348 1.455406666 4.52E-26 1050 | 1349 1.455403447 4.51E-26 1051 | 1350 1.455400229 4.49E-26 1052 | 1351 1.455396891 4.48E-26 1053 | 1352 1.455393791 4.46E-26 1054 | 1353 1.455390453 4.44E-26 1055 | 1354 1.455387235 4.43E-26 1056 | 1355 1.455384135 4.41E-26 1057 | 1356 1.455380797 4.4E-26 1058 | 1357 1.455377579 4.38E-26 1059 | 1358 1.455374479 4.37E-26 1060 | 1359 1.455371261 4.35E-26 1061 | 1360 1.455368042 4.34E-26 1062 | 1361 1.455364823 4.32E-26 1063 | 1362 1.455361605 4.3E-26 1064 | 1363 1.455358505 4.29E-26 1065 | 1364 1.455355287 4.27E-26 1066 | 1365 1.455352426 4.26E-26 1067 | 1366 1.45535028 4.24E-26 1068 | 1367 1.455348015 4.23E-26 1069 | 1368 1.455345869 4.22E-26 1070 | 1369 1.455343723 4.2E-26 1071 | 1370 1.455341458 4.19E-26 1072 | 1371 1.455339313 4.17E-26 1073 | 1372 1.455337167 4.16E-26 1074 | 1373 1.455334902 4.14E-26 1075 | 1374 1.455332756 4.13E-26 1076 | 1375 1.45533061 4.12E-26 1077 | 1376 1.455328345 4.1E-26 1078 | 1377 1.4553262 4.09E-26 1079 | 1378 1.455324054 4.07E-26 1080 | 1379 1.455321908 4.06E-26 1081 | 1380 1.455319762 4.05E-26 1082 | 1381 1.455317616 4.03E-26 1083 | 1382 1.455315471 4.02E-26 1084 | 1383 1.455313325 4E-26 1085 | 1384 1.455311179 3.99E-26 1086 | 1385 1.455309033 3.98E-26 1087 | 1386 1.455306888 3.96E-26 1088 | 1387 1.455304742 3.95E-26 1089 | 1388 1.455302477 3.94E-26 1090 | 1389 1.455299258 3.92E-26 1091 | 1390 1.455296159 3.91E-26 1092 | 1391 1.455293059 3.9E-26 1093 | 1392 1.455289841 3.88E-26 1094 | 1393 1.455286741 3.87E-26 1095 | 1394 1.455283761 3.86E-26 1096 | 1395 1.455280662 3.85E-26 1097 | 1396 1.455277562 3.83E-26 1098 | 1397 1.455274463 3.82E-26 1099 | 1398 1.455271363 3.81E-26 1100 | 1399 1.455268264 3.8E-26 1101 | 1400 1.455265164 3.78E-26 1102 | 1401 1.455262065 3.77E-26 1103 | 1402 1.455258965 3.76E-26 1104 | 1403 1.455255985 3.75E-26 1105 | 1404 1.455252886 3.73E-26 1106 | 1405 1.455249786 3.72E-26 1107 | 1406 1.455246806 3.71E-26 1108 | 1407 1.455243826 3.7E-26 1109 | 1408 1.455240726 3.68E-26 1110 | 1409 1.455237746 3.67E-26 1111 | 1410 1.455234647 3.66E-26 1112 | 1411 1.455231667 3.65E-26 1113 | 1412 1.455229044 3.63E-26 1114 | 1413 1.455227494 3.62E-26 1115 | 1414 1.455225945 3.61E-26 1116 | 1415 1.455224395 3.6E-26 1117 | 1416 1.455222845 3.59E-26 1118 | 1417 1.455221295 3.58E-26 1119 | 1418 1.455219746 3.57E-26 1120 | 1419 1.455218077 3.55E-26 1121 | 1420 1.455216527 3.54E-26 1122 | 1421 1.455215096 3.53E-26 1123 | 1422 1.455213547 3.52E-26 1124 | 1423 1.455211997 3.51E-26 1125 | 1424 1.455210567 3.5E-26 1126 | 1425 1.455208898 3.49E-26 1127 | 1426 1.455207348 3.48E-26 1128 | 1427 1.455205917 3.46E-26 1129 | 1428 1.455204368 3.45E-26 1130 | 1429 1.455202818 3.44E-26 1131 | 1430 1.455201387 3.43E-26 1132 | 1431 1.455199838 3.42E-26 1133 | 1432 1.455198288 3.41E-26 1134 | 1433 1.455196738 3.4E-26 1135 | 1434 1.455195308 3.39E-26 1136 | 1435 1.455193758 3.38E-26 1137 | 1436 1.455192208 3.37E-26 1138 | 1437 1.455190182 3.35E-26 1139 | 1438 1.455187798 3.34E-26 1140 | 1439 1.455185175 3.33E-26 1141 | 1440 1.455182791 3.32E-26 1142 | 1441 1.455180168 3.31E-26 1143 | 1442 1.455177784 3.3E-26 1144 | 1443 1.455175281 3.29E-26 1145 | 1444 1.455172777 3.28E-26 1146 | 1445 1.455170274 3.27E-26 1147 | 1446 1.45516789 3.26E-26 1148 | 1447 1.455165267 3.25E-26 1149 | 1448 1.455162883 3.24E-26 1150 | 1449 1.455160379 3.23E-26 1151 | 1450 1.455157876 3.22E-26 1152 | 1451 1.455155492 3.21E-26 1153 | 1452 1.455152988 3.2E-26 1154 | 1453 1.455150604 3.19E-26 1155 | 1454 1.455148101 3.18E-26 1156 | 1455 1.455145597 3.17E-26 1157 | 1456 1.455143213 3.16E-26 1158 | 1457 1.455140829 3.15E-26 1159 | 1458 1.455138326 3.14E-26 1160 | 1459 1.455135942 3.13E-26 1161 | 1460 1.455133438 3.12E-26 1162 | 1461 1.455131054 3.11E-26 1163 | 1462 1.455128551 3.1E-26 1164 | 1463 1.455126762 3.1E-26 1165 | 1464 1.455124855 3.09E-26 1166 | 1465 1.455123067 3.08E-26 1167 | 1466 1.455121279 3.07E-26 1168 | 1467 1.455119491 3.06E-26 1169 | 1468 1.455117702 3.05E-26 1170 | 1469 1.455115914 3.04E-26 1171 | 1470 1.455114126 3.03E-26 1172 | 1471 1.455112338 3.02E-26 1173 | 1472 1.455110431 3.01E-26 1174 | 1473 1.455108762 3.01E-26 1175 | 1474 1.455106974 3E-26 1176 | 1475 1.455105186 2.99E-26 1177 | 1476 1.455103397 2.98E-26 1178 | 1477 1.455101609 2.97E-26 1179 | 1478 1.455099821 2.96E-26 1180 | 1479 1.455098033 2.95E-26 1181 | 1480 1.455096364 2.94E-26 1182 | 1481 1.455094457 2.93E-26 1183 | 1482 1.455092788 2.93E-26 1184 | 1483 1.455091 2.92E-26 1185 | 1484 1.455089211 2.91E-26 1186 | 1485 1.455087423 2.9E-26 1187 | 1486 1.455085754 2.89E-26 1188 | 1487 1.455083966 2.88E-26 1189 | 1488 1.455082178 2.87E-26 1190 | 1489 1.455080271 2.86E-26 1191 | 1490 1.455077529 2.86E-26 1192 | 1491 1.455074906 2.85E-26 1193 | 1492 1.455072284 2.84E-26 1194 | 1493 1.455069661 2.83E-26 1195 | 1494 1.455066919 2.82E-26 1196 | 1495 1.455064297 2.82E-26 1197 | 1496 1.455061674 2.81E-26 1198 | 1497 1.455059052 2.8E-26 1199 | 1498 1.45505631 2.79E-26 1200 | 1499 1.455053687 2.78E-26 1201 | 1500 1.455051064 2.78E-26 1202 | -------------------------------------------------------------------------------- /tmm_fast/plotting_helper.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.colors as colors 3 | import matplotlib.cm as cm 4 | 5 | def plot_stacks(ax, indexes, thickness, labels=None, show_material=True): 6 | ''' 7 | Plots material layers on top of each other with the refractive index of the layer in colorcode. 8 | 9 | Parameter: 10 | ax: matplotlib axes object 11 | axes where the plot will put into 12 | 13 | indexes: array_like 14 | array of real or complex refractive indexes 15 | 16 | thickness: array_like or list of array_like 17 | if provided an array of thicknesses, plots one stack 18 | if provided a list of arrays of thicknesses, plots them next to each other 19 | the values should be given in meters (ie. 4e-6 for a 4 micron thick layer) 20 | 21 | Key word arguments: (optional) 22 | labels: str or list of str 23 | Labels for the stack, if provided a list of str, the length must exactly match the 24 | length of the list of thicknesses 25 | 26 | show_material: boolean 27 | If True, displays the real refractive index of the first wavelength which is computed 28 | directly in the depiction of the layer. If the layer is too thin to properly display 29 | the refractive index, it is suppresed. 30 | 31 | Returns: 32 | ax: matplotlib axes object 33 | axes with the plotted stacks for further modification 34 | 35 | cmap: matplotlib colormap object 36 | colormap to show 37 | 38 | 39 | Example: 40 | fig, ax = plt.subplots(1,1) 41 | indexes = np.array([2, 1, 2.5, 1.6]) 42 | thickness = np.array([5, 7, 3, 6]*1e-6) 43 | labels = 'this is my stack' 44 | ax, cmap = plot_stacks(ax, indexes, thickness, labels=labels ) 45 | plt.show() 46 | ''' 47 | mat={'1.4585':'Si02', 48 | '2.3403':'Nb205', 49 | '2.3991':'GaN'} 50 | 51 | if type(indexes) is not list: 52 | minmax = colors.Normalize(vmin=min(indexes)-1, vmax=max(indexes)+1) 53 | indexes = indexes.real[::-1] 54 | else: 55 | for i in range(len(indexes)): 56 | indexes[i] = indexes[i].real[::-1] 57 | # indexes = indexes.real[::-1] 58 | minmax = colors.Normalize(vmin=min(indexes[0])-1, vmax=max(indexes[0])+1) 59 | cmap = cm.ScalarMappable(norm= minmax, cmap=cm.rainbow) 60 | if labels is None: # if no labels are provided, numerate the stacks 61 | labels = str(np.arange(len(thickness))) 62 | if type(thickness) is list: 63 | max_stack_height = np.max([np.sum(k)*1e6 for k in thickness]) 64 | for j, thick in enumerate(thickness): 65 | position = j*0.4 66 | for i, layer in enumerate(np.cumsum(thick*1e6)[::-1]): 67 | ax.bar(position, layer, 0.36, color = cmap.to_rgba(indexes[j][i]) ) 68 | if show_material and ((thick*1e6)[::-1][i] > max_stack_height/22): 69 | text = mat[str(indexes[j][i])] if str(indexes[j][i]) in mat else 'n='+str(indexes[j][i]) 70 | ax.text(position-0.175, layer-0.008*max_stack_height, text, va='top', c='gray') 71 | ax.set_xticks(np.arange(0, 0.4*len(thickness), 0.401)) # funny trick to make sure the labels 72 | # are centered beneath the stack 73 | if labels is not None: 74 | ax.set_xticklabels(labels) 75 | else: 76 | ax.set_xticklabels([i+1 for i in range(len(thickness))]) 77 | else: 78 | total_stack_height = np.sum(thickness)*1e6 79 | for i, layer in enumerate(np.cumsum(thickness*1e6)[::-1]): 80 | ax.bar(0, layer, 0.2, color = cmap.to_rgba(indexes[i]) ) 81 | if show_material and ((thickness*1e6)[::-1][i] > total_stack_height/22): 82 | text = mat[str(indexes[i])] if str(indexes[i]) in mat else 'n='+str(indexes[i]) 83 | ax.text(-0.098, layer-0.008*total_stack_height, text, va='top', c='gray') 84 | ax.set_ylim(0, (np.sum(thickness)*1.05*1e6)) 85 | ax.xaxis.set_visible(False) 86 | ax.set_ylabel(r'Thickness in $\mu$m') 87 | 88 | return ax, cmap -------------------------------------------------------------------------------- /tmm_fast/vectorized_incoherent_tmm.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from .vectorized_tmm_dispersive_multistack import coh_vec_tmm_disp_mstack as coh_tmm 4 | from .vectorized_tmm_dispersive_multistack import ( 5 | SnellLaw_vectorized, 6 | interface_r_vec, 7 | interface_t_vec, 8 | T_from_t_vec, 9 | R_from_r_vec, 10 | ) 11 | 12 | from typing import Union 13 | 14 | 15 | def inc_vec_tmm_disp_lstack( 16 | pol: str, 17 | N: torch.Tensor, 18 | D: torch.Tensor, 19 | mask: list, 20 | theta: Union[np.ndarray, torch.Tensor], 21 | lambda_vacuum: Union[np.ndarray, torch.Tensor], 22 | device: str = "cpu", 23 | timer: bool = False, 24 | ) -> dict: 25 | """ 26 | Parallelized computation of reflection and transmission for incoherent and coherent 27 | light spectra that traverse a bunch of multilayer thin-films with dispersive materials. 28 | This implementation in PyTorch naturally allows: 29 | - GPU accelerated computations 30 | - To compute gradients regarding the multilayer thin-film (i.e. N, T) thanks to Pytorch Autograd 31 | 32 | However, the input can also be a numpy array format. 33 | Although all internal computations are processed via PyTorch, the output data is converted to numpy arrays again. 34 | Hence, the use of numpy input may increase computation time due to data type conversions. 35 | 36 | Parameters: 37 | ----------- 38 | pol : str 39 | Polarization of the light, accepts only 's' or 'p' 40 | N : torch.Tensor 41 | Complex refractive indices for all layers. The tensor must have shape 42 | [n_stacks, n_layers] for dispersionless materials or [n_stacks, n_layers, n_lambda] 43 | for dispersive materials. If only 44 | D : torch.Tensor 45 | Layer thicknesses in [m] for all incoherent and coherent layers. Must have shape 46 | [n_stacks, n_layers] 47 | mask : list 48 | Specifies all the coherent substack. A coherent substack must be adjacent to an incoherent layer. 49 | Eg. mask = [[2,3,4], [6,7], [10, 11, 12]] specifies 3 coherent substacks for a stack of total 50 | length >= 14. the incoherent layers are 0, 1, 5, 8, 9, 13 and any further layers. 51 | Note that the function can handle parallel stacks but the mask must be identical for all parallel 52 | stacks 53 | theta : torch.tensor 54 | Angles of incidence in [rad] of the incoming light in the first layer. Must have shape 55 | [n_theta] 56 | lambda_vacuum : torch.tensor 57 | Vacuum wavelengths of the light in [m]. Must have shape 58 | [n_wl] 59 | device : str 60 | Device on which the computation should be done. Either "cpu" or "cuda" 61 | 62 | Returns: 63 | -------- 64 | dict : 65 | "R": torch.Tensor 66 | Reflectivity of the entire stack of incoherent and coherent layers 67 | "T": torch.Tensor 68 | Transmissivity of the entire stack of incoherent and coherent layers 69 | "L": torch.Tensor 70 | Interface matrices see Byrnes Eq. 28 71 | 'coh_tmm_f': dict 72 | Forward result for the coherent substacks in order. The dict contains the 73 | results of a normal coherent stack 74 | 'coh_tmm_b': torch.Tensor 75 | Backward result for the coherent substacks in order. The dict contains the 76 | results of a normal coherent stack 77 | 'P': torch.Tensor 78 | Absorption in the incoherent layers 79 | 'th_list': torch.Tensor 80 | Complex angles according to snells law in all layers 81 | 82 | Example: 83 | -------- 84 | 85 | num_layers = 6 86 | num_stacks = 2 87 | n_wl = 75 88 | n_th = 45 89 | pol = polarization = 's' 90 | wl = wavelengths = torch.linspace(400, 1200, n_wl) * (10**(-9)) 91 | th = incidence_angles = torch.linspace(0, 89, n_th) * (np.pi/180) 92 | 93 | # the mask specifies that layer 1 and 2 form a coherent substack and 94 | # layer 4 forms another coherent substack 95 | mask = [[1, 2], [4]] 96 | 97 | N = refracive_indices = torch.ones( 98 | (num_stacks, num_layers, wl.shape[0]), 99 | dtype=torch.complex128 100 | ) 101 | 102 | N[:, 1] = 1.3 + .003j 103 | N[:, 2] = 2.2 + .0j 104 | N[:, 3] = 1.3 + .003j 105 | N[:, 4] = 1.1 + .0j 106 | 107 | D = layer_thicknesses = torch.empty((n_stacks, n_layers), dtype=torch.float128) 108 | D[:, 0] = np.inf 109 | # test how a a change of the first layer thickness changes the result 110 | D[0, 1] = 200e-9 111 | D[1, 1] = 400e-9 112 | 113 | D[:, 2] = 200e-9 114 | D[:, 3] = 15000e-9 115 | D[:, 4] = 300e-9 116 | D[:, -1] = np.inf 117 | 118 | result_dict = inc_tmm_fast(pol, N, D, mask, th, wl, device='cpu') 119 | 120 | """ 121 | n_lambda = len(lambda_vacuum) 122 | n_theta = len(theta) 123 | n_layers = D.shape[1] 124 | n_stack = D.shape[0] 125 | imask = get_imask(mask, n_layers) 126 | 127 | coh_res_f = [] 128 | coh_res_b = [] 129 | 130 | L_coh_loc = np.argwhere(np.diff(imask) != 1).flatten() 131 | L_inc_loc = np.argwhere(np.diff(imask) == 1).flatten() 132 | 133 | n_L_ = len(imask) -1 134 | # matrix of Reflectivity and Transmissivity of the layer interfaces 135 | requires_grad = True if (D.requires_grad or N.requires_grad) else False 136 | L_ = torch.empty((n_stack, n_L_, n_theta, n_lambda, 2, 2)).requires_grad_( 137 | requires_grad 138 | ) 139 | 140 | snell_theta = SnellLaw_vectorized( 141 | N.type(torch.complex128), theta.type(torch.complex128) 142 | ) # propagation angle in every layer 143 | 144 | # first, the coherent substacks are evaluated with the adjacent incoherent stacks as input 145 | # and output layer. Therefore, Im(N) of the incoherent layers are set to zero for the 146 | # coherent evaluation. The absorption for the incoherent layers are calculated later 147 | for i, m in zip(L_coh_loc, mask): # eg m = [4,5,6] 148 | m_ = np.arange(m[0]-1, m[-1]+2, 1, dtype=int) 149 | N_ = N[:, m_] 150 | d = D[:, m_] 151 | d[:, 0] = d[:, -1] = np.inf 152 | forward = coh_tmm( 153 | pol, N_, d, snell_theta[0, :, m_[0], 0], lambda_vacuum, device 154 | ) 155 | # the substack must be evaluated in both directions since we can have an incoming wave from the output side 156 | # (a reflection from an incoherent layer) and Reflectivit/Transmissivity can be different depending on the direction 157 | backward = coh_tmm( 158 | pol, 159 | N_.flip([1]), 160 | d.flip([1]), 161 | snell_theta[0, :, m_[-1], 0], 162 | lambda_vacuum, 163 | device, 164 | ) 165 | T_f = forward["T"] # [n_stack, n_lambda, n_theta] 166 | T_b = backward["T"] 167 | R_f = forward["R"] 168 | R_b = backward["R"] 169 | 170 | coh_res_f.append(forward) 171 | coh_res_b.append(backward) 172 | # sanity_checker(T_f) 173 | # sanity_checker(T_b) 174 | # sanity_checker(R_f) 175 | # sanity_checker(R_b) 176 | 177 | L_[:, i, :, :, 0, 0] = 1.0 / T_f 178 | L_[:, i, :, :, 0, 1] = -R_b / T_f 179 | L_[:, i, :, :, 1, 0] = R_f / T_f 180 | L_[:, i, :, :, 1, 1] = ( T_b * T_f - R_b * R_f ) / T_f 181 | 182 | # Now, the incoherent layers are evaluated. In principle, the treatment is identical 183 | # to a coherent layer but the phase dependency is lost at each interface. 184 | 185 | for i, (k, m) in enumerate(zip(imask[:-1], np.diff(imask))): 186 | # we only evaluate interfaces between two adjacent incoherent layers 187 | if m == 1: 188 | tf = interface_t_vec( 189 | pol, 190 | N[:, k][:, None], 191 | N[:, k + 1][:, None], 192 | snell_theta[:, :, k][:, :, None], 193 | snell_theta[:, :, k + 1][:, :, None], 194 | )[:, :, :, 0] 195 | T_f = T_from_t_vec( 196 | pol, 197 | tf, 198 | N[:, k], 199 | N[:, k + 1], 200 | snell_theta[:, :, k], 201 | snell_theta[:, :, k + 1], 202 | ) 203 | tb = interface_t_vec( 204 | pol, 205 | N[:, k + 1][:, None], 206 | N[:, k][:, None], 207 | snell_theta[:, :, k + 1][:, :, None], 208 | snell_theta[:, :, k][:, :, None], 209 | )[:, :, :, 0] 210 | T_b = T_from_t_vec( 211 | pol, 212 | tb, 213 | N[:, k + 1], 214 | N[:, k], 215 | snell_theta[:, :, k + 1], 216 | snell_theta[:, :, k], 217 | ) 218 | rf = interface_r_vec( 219 | pol, 220 | N[:, k][:, None], 221 | N[:, k + 1][:, None], 222 | snell_theta[:, :, k][:, :, None], 223 | snell_theta[:, :, k + 1][:, :, None], 224 | )[:, :, :, 0] 225 | R_f = R_from_r_vec(rf) 226 | rb = interface_r_vec( 227 | pol, 228 | N[:, k + 1][:, None], 229 | N[:, k][:, None], 230 | snell_theta[:, :, k + 1][:, :, None], 231 | snell_theta[:, :, k][:, :, None], 232 | )[:, :, :, 0] 233 | R_b = R_from_r_vec(rb) 234 | 235 | L_[:, i, :, :, 0, 0] = 1.0 / T_f 236 | L_[:, i, :, :, 0, 1] = -R_b / T_f 237 | L_[:, i, :, :, 1, 0] = R_f / T_f 238 | L_[:, i, :, :, 1, 1] = ( T_b * T_f - R_b * R_f ) / T_f 239 | P_ = None 240 | for i, k in enumerate(imask[1:-1], 1): 241 | n_costheta = torch.einsum( 242 | "ik,ijk->ijk", N[:, k], torch.cos(snell_theta[:, :, k]) 243 | ).imag # [n_stack, n_theta, n_lambda] 244 | P = torch.exp( 245 | -4. 246 | * np.pi 247 | * (torch.einsum("ijk,k,i->ijk", n_costheta, 1 / lambda_vacuum, D[:, k])) 248 | ) 249 | P_ = torch.zeros((*P.shape, 2, 2)) # [n_stack, n_th, n_wl, 2, 2] 250 | P_[..., 0, 0] = 1/P 251 | P_[..., 1, 1] = P 252 | L_[:, i] = torch.einsum("ijklm,ijkmn->ijkln", P_, L_[:, i]) 253 | 254 | # multiply all interfaces together 255 | L_tilde = L_[:, 0] 256 | for i in range(1, n_L_): 257 | L_tilde = torch.einsum("ijklm,ijkmn->ijkln", L_tilde, L_[:, i]) 258 | 259 | R = L_tilde[..., 1, 0] / (L_tilde[..., 0, 0] + np.finfo(float).eps) 260 | 261 | T = 1 / (L_tilde[..., 0, 0] + np.finfo(float).eps) 262 | 263 | return {"R": R, "T": T, "L": L_, 'coh_tmm_f':coh_res_f, 'coh_tmm_b':coh_res_b, 'P':P_, 'th_list':snell_theta} 264 | 265 | 266 | def sanity_checker(input): 267 | assert ( 268 | 1.0 >= input.any() >= 0.0 269 | ).item(), "Some values are out of the accepted range of [0,1]" 270 | 271 | def get_imask(mask, n_layers): 272 | mask = [item for sublist in mask for item in sublist] 273 | imask = np.isin(np.arange(n_layers, dtype=int), mask, invert=True) 274 | return np.arange(n_layers, dtype=int)[imask] 275 | -------------------------------------------------------------------------------- /tmm_fast/vectorized_tmm_dispersive_multistack.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from numpy import pi 3 | import torch 4 | 5 | from typing import Union 6 | import sys 7 | from warnings import warn 8 | EPSILON = sys.float_info.epsilon 9 | 10 | def coh_vec_tmm_disp_mstack(pol:str, 11 | N:Union[np.ndarray, torch.Tensor], 12 | T:Union[np.ndarray, torch.Tensor], 13 | Theta:Union[np.ndarray, torch.Tensor], 14 | lambda_vacuum:Union[np.ndarray, torch.Tensor], 15 | device:str='cpu', 16 | timer:bool=False) -> dict: 17 | """ 18 | Parallelized computation of reflection and transmission for coherent light spectra that traverse 19 | a bunch of multilayer thin-films with dispersive materials. 20 | This implementation in PyTorch naturally allows: 21 | - GPU accelerated computations 22 | - To compute gradients regarding the multilayer thin-film (i.e. N, T) thanks to Pytorch Autograd 23 | 24 | However, the input can also be a numpy array format. 25 | Although all internal computations are processed via PyTorch, the output data is converted to numpy arrays again. 26 | Hence, the use of numpy input may increase computation time due to data type conversions. 27 | 28 | Parameters: 29 | ----------- 30 | pol : str 31 | Polarization of the light, accepts only 's' or 'p' 32 | N : Tensor or array 33 | PyTorch Tensor or numpy array of shape [S x L x W] with complex or real entries which contain the refractive 34 | indices at the wavelengths of interest: 35 | S is the number of multi-layer thin films, L is the number of layers for each thin film, W is the number of 36 | wavelength considered. Note that the first and last layer must feature real valued () 37 | refractive indicies, i.e. imag(N[:, 0, :]) = 0 and imag(N[:, -1, :]) = 0. 38 | T : Tensor or array 39 | Holds the layer thicknesses of the individual layers for a bunch of thin films in nanometer. 40 | T is of shape [S x L] with real-valued entries; infinite values are allowed for the first and last layers only! 41 | Theta : Tensor or array 42 | Theta is a tensor or array that determines the angles with which the light propagates in the injection layer. 43 | Theta is of shape [A] and holds the incidence angles [rad] in its entries. 44 | lambda_vacuum : Tensor or numpy array 45 | Vacuum wavelengths for which reflection and transmission are computed given a bunch of thin films. 46 | It is of shape [W] and holds the wavelengths in nanometer. 47 | device : Str 48 | Computation device, accepts ether 'cuda' or 'cpu'; GPU acceleration can lower the computational time especially 49 | for computation involving large tensors 50 | timer: Boolean 51 | Determines whether to track times for data pushing on CPU or GPU and total computation time; see output 52 | information for details on how to read out time 53 | 54 | Returns: 55 | -------- 56 | output : Dict 57 | Keys: 58 | 'r' : Tensor or array of Fresnel coefficients of reflection for each stack (over angle and wavelength) 59 | 't' : Tensor or array of Fresnel coefficients of transmission for each stack (over angle and wavelength) 60 | 'R' : Tensor or array of Reflectivity / Reflectance for each stack (over angle and wavelength) 61 | 'T' : Tensor or array of Transmissivity / Transmittance for each stack (over angle and wavelength) 62 | Each of these tensors or arrays is of shape [S x A x W] 63 | optional output: list of two floats if timer=True 64 | first entry holds the push time [sec] that is the time required to push the input data on the specified 65 | device (i.e. cpu oder cuda), the second entry holds the total computation time [sec] (push time + tmm) 66 | 67 | Remarks and prior work from Byrnes: 68 | ----------------------------------- 69 | Main "coherent transfer matrix method" calc. Given parameters of a stack, 70 | calculates everything you could ever want to know about how light 71 | propagates in it. (If performance is an issue, you can delete some of the 72 | calculations without affecting the rest.) 73 | pol is light polarization, "s" or "p". 74 | n_list is the list of refractive indices, in the order that the light would 75 | pass through them. The 0'th element of the list should be the semi-infinite 76 | medium from which the light enters, the last element should be the semi- 77 | infinite medium to which the light exits (if any exits). 78 | th_0 is the angle of incidence: 0 for normal, pi/2 for glancing. 79 | Remember, for a dissipative incoming medium (n_list[0] is not real), th_0 80 | should be complex so that n0 sin(th0) is real (intensity is constant as 81 | a function of lateral position). 82 | d_list is the list of layer thicknesses (front to back). Should correspond 83 | one-to-one with elements of n_list. First and last elements should be "inf". 84 | lam_vac is vacuum wavelength of the light. 85 | Outputs the following as a dictionary (see manual for details) 86 | * r--reflection amplitude 87 | * t--transmission amplitude 88 | * R--reflected wave power (as fraction of incident) 89 | * T--transmitted wave power (as fraction of incident) 90 | * power_entering--Power entering the first layer, usually (but not always) 91 | equal to 1-R (see manual). 92 | * vw_list-- n'th element is [v_n,w_n], the forward- and backward-traveling 93 | amplitudes, respectively, in the n'th medium just after interface with 94 | (n-1)st medium. 95 | * kz_list--normal component of complex angular wavenumber for 96 | forward-traveling wave in each layer. 97 | * th_list--(complex) propagation angle (in radians) in each layer 98 | * pol, n_list, d_list, th_0, lam_vac--same as input 99 | """ 100 | 101 | if timer: 102 | import time 103 | starttime = time.time() 104 | datatype = check_datatype(N, T, lambda_vacuum, Theta) 105 | # check uniform data types (e.g. only np.array or torch.tensor) -> save this type 106 | N = converter(N, device) 107 | T = converter(T, device) 108 | lambda_vacuum = converter(lambda_vacuum, device) 109 | Theta = converter(Theta, device) 110 | squeezed_N = False 111 | squeezed_T = False 112 | if N.ndim < 3: 113 | squeezed_N = True 114 | N = N.unsqueeze(0) 115 | if T.ndim < 2: 116 | squeezed_T = True 117 | T = T.unsqueeze(0) 118 | assert squeezed_N == squeezed_T, 'N and T are not of same shape, as they are of dimensions ' + str(N.ndim) + ' and ' + str(T.ndim) 119 | if timer: 120 | push_time = time.time() - starttime 121 | num_layers = T.shape[1] 122 | num_stacks = T.shape[0] 123 | num_angles = Theta.shape[0] 124 | num_wavelengths = lambda_vacuum.shape[0] 125 | check_inputs(N, T, lambda_vacuum, Theta) 126 | N.imag = torch.clamp(N.imag, max=35.) 127 | 128 | # if a constant refractive index is used (no dispersion) extend the tensor 129 | if N.ndim == 2: 130 | N = torch.tile(N, (num_wavelengths, 1)).T 131 | 132 | # SnellThetas is a tensor, for each stack and layer, the angle that the light travels 133 | # through the layer. Computed with Snell's law. Note that the "angles" may be complex! 134 | SnellThetas = SnellLaw_vectorized(N, Theta) 135 | 136 | 137 | theta = 2 * np.pi * torch.einsum('skij,sij->skij', torch.cos(SnellThetas), N) # [theta,d, lambda] 138 | kz_list = torch.einsum('sijk,k->skij', theta, 1 / lambda_vacuum) # [lambda, theta, d] 139 | 140 | # kz is the z-component of (complex) angular wavevector for the forward-moving 141 | # wave. Positive imaginary part means decaying. 142 | 143 | # delta is the total phase accrued by traveling through a given layer. 144 | # Ignore warning about inf multiplication 145 | 146 | 147 | delta = torch.einsum('skij,sj->skij', kz_list, T) 148 | 149 | # check for opacity. If too much of the optical power is absorbed in a layer 150 | # it can lead to numerical instability. 151 | if torch.any(delta.imag > 35.): 152 | delta.imag = torch.clamp(delta.imag, max=35.) 153 | warn('Opacity warning. The imaginary part of the refractive index is clamped to 35i for numerical stability.\n'+ 154 | 'You might encounter problems with gradient computation...') 155 | 156 | 157 | # t_list and r_list hold the transmission and reflection coefficients from 158 | # the Fresnel Equations 159 | 160 | t_list = interface_t_vec(pol, N[:, :-1, :], N[:, 1:, :], SnellThetas[:, :, :-1, :], SnellThetas[:, :, 1:, :]) 161 | r_list = interface_r_vec(pol, N[:, :-1, :], N[:, 1:, :], SnellThetas[:, :, :-1, :], SnellThetas[:, :, 1:, :]) 162 | 163 | # A ist the propagation term for matrix optic and holds the appropriate accumulated phase for the thickness 164 | # of each layer 165 | A = torch.exp(1j * delta[:, :, :, 1:-1]) 166 | F = r_list[:, :, :, 1:] 167 | 168 | # M_list holds the transmission and reflection matrices from matrix-optics 169 | 170 | M_list = torch.zeros((num_stacks, num_angles, num_wavelengths, num_layers, 2, 2), dtype=torch.complex128, device=device) 171 | M_list[:, :, :, 1:-1, 0, 0] = torch.einsum('shji,sjhi->sjhi', 1 / (A + np.finfo(float).eps), 1 / t_list[:, :, :, 1:]) 172 | M_list[:, :, :, 1:-1, 0, 1] = torch.einsum('shji,sjhi->sjhi', 1 / (A + np.finfo(float).eps), F / t_list[:, :, :, 1:]) 173 | M_list[:, :, :, 1:-1, 1, 0] = torch.einsum('shji,sjhi->sjhi', A, F / t_list[:, :, :, 1:]) 174 | M_list[:, :, :, 1:-1, 1, 1] = torch.einsum('shji,sjhi->sjhi', A, 1 / t_list[:, :, :, 1:]) 175 | Mtilde = torch.empty((num_stacks, num_angles, num_wavelengths, 2, 2), dtype=torch.complex128, device=device) 176 | Mtilde[:, :, :] = make_2x2_tensor(1, 0, 0, 1, dtype=torch.complex128) 177 | 178 | # contract the M_list matrix along the dimension of the layers, all 179 | for i in range(1, num_layers - 1): 180 | Mtilde = torch.einsum('sijkl,sijlm->sijkm', Mtilde, M_list[:, :, :, i]) 181 | 182 | # M_r0 accounts for the first and last stack where the translation coefficients are 1 183 | # todo: why compute separately? 184 | M_r0 = torch.empty((num_stacks, num_angles, num_wavelengths, 2, 2), dtype=torch.cfloat, device=device) 185 | M_r0[:, :, :, 0, 0] = 1 186 | M_r0[:, :, :, 0, 1] = r_list[:, :, :, 0] 187 | M_r0[:, :, :, 1, 0] = r_list[:, :, :, 0] 188 | M_r0[:, :, :, 1, 1] = 1 189 | M_r0 = torch.einsum('sijkl,sij->sijkl', M_r0, 1 / t_list[:, :, :, 0]) 190 | 191 | Mtilde = torch.einsum('shijk,shikl->shijl', M_r0, Mtilde) 192 | 193 | # Net complex transmission and reflection amplitudes 194 | r = Mtilde[:, :, :, 1, 0] / (Mtilde[:, :, :, 0, 0] + np.finfo(float).eps) 195 | t = 1 / (Mtilde[:, :, :, 0, 0] + np.finfo(float).eps) 196 | 197 | # Net transmitted and reflected power, as a proportion of the incoming light 198 | # power. 199 | R = R_from_r_vec(r) 200 | T = T_from_t_vec(pol, t, N[:, 0], N[:, -1], SnellThetas[:, :, 0], SnellThetas[:, :, -1]) 201 | 202 | if squeezed_T and r.shape[0] == 1: 203 | r = torch.reshape(r, (r.shape[1], r.shape[2])) 204 | R = torch.reshape(R, (R.shape[1], R.shape[2])) 205 | T = torch.reshape(T, (T.shape[1], T.shape[2])) 206 | t = torch.reshape(t, (t.shape[1], t.shape[2])) 207 | 208 | if datatype is np.ndarray: 209 | r = numpy_converter(r) 210 | t = numpy_converter(t) 211 | R = numpy_converter(R) 212 | T = numpy_converter(T) 213 | 214 | if timer: 215 | total_time = time.time() - starttime 216 | return {'r': r, 't': t, 'R': R, 'T': T}, [push_time, total_time] 217 | else: 218 | return {'r': r, 't': t, 'R': R, 'T': T} 219 | 220 | def SnellLaw_vectorized(n, th): 221 | """ 222 | return list of angle theta in each layer based on angle th_0 in layer 0, 223 | using Snell's law. n_list is index of refraction of each layer. Note that 224 | "angles" may be complex!! 225 | """ 226 | # Important that the arcsin here is numpy.lib.scimath.arcsin, not 227 | # numpy.arcsin! (They give different results e.g. for arcsin(2).) 228 | if th.dtype != torch.complex128: 229 | warn('there is some problem with theta, the dtype is not complex') 230 | if n.dtype != torch.complex128: 231 | warn('there is some problem with n, the dtype is not conplex') 232 | th = th if th.dtype == torch.complex128 else th.type(torch.complex128) 233 | n = n if n.dtype == torch.complex128 else n.type(torch.complex128) 234 | 235 | n0_ = torch.einsum('hk,j,hik->hjik', n[:,0], torch.sin(th), 1/n) 236 | angles = torch.asin(n0_) 237 | 238 | # The first and last entry need to be the forward angle (the intermediate 239 | # layers don't matter, see https://arxiv.org/abs/1603.02720 Section 5) 240 | 241 | angles[:, :, 0] = torch.where( 242 | is_not_forward_angle(n[:, 0], angles[:, :, 0]).bool(), 243 | pi - angles[:, :, 0], 244 | angles[:, :, 0], 245 | ) 246 | angles[:, :, -1] = torch.where( 247 | is_not_forward_angle(n[:, -1], angles[:, :, -1]).bool(), 248 | pi - angles[:, :, -1], 249 | angles[:, :, -1], 250 | ) 251 | 252 | return angles 253 | 254 | def is_not_forward_angle(n, theta): 255 | """ 256 | if a wave is traveling at angle theta from normal in a medium with index n, 257 | calculate whether or not this is the forward-traveling wave (i.e., the one 258 | going from front to back of the stack, like the incoming or outgoing waves, 259 | but unlike the reflected wave). For real n & theta, the criterion is simply 260 | -pi/2 < theta < pi/2, but for complex n & theta, it's more complicated. 261 | See https://arxiv.org/abs/1603.02720 appendix D. If theta is the forward 262 | angle, then (pi-theta) is the backward angle and vice-versa. 263 | """ 264 | # n = [lambda] 265 | # theta = [theta, lambda] 266 | 267 | error_string = ("It's not clear which beam is incoming vs outgoing. Weird index maybe?\n" 268 | "n: " + str(n) + " angle: " + str(theta)) 269 | 270 | # Case gain material 271 | assert (n.real * n.imag >= 0).all(), ("For materials with gain, it's ambiguous which " 272 | "beam is incoming vs outgoing. See " 273 | "https://arxiv.org/abs/1603.02720 Appendix C.\n" 274 | "n: " + str(n) + " angle: " + str(theta)) 275 | n = n.unsqueeze(1) 276 | ncostheta = torch.cos(theta) * n 277 | assert ncostheta.shape == theta.shape, 'ncostheta and theta shape doesnt match' 278 | answer = torch.empty_like(ncostheta, dtype=torch.bool) 279 | # Either evanescent decay or lossy medium. Either way, the one that 280 | # decays is the forward-moving wave 281 | answer = (abs(ncostheta.imag) > 100 * EPSILON) * (ncostheta.imag > 0) 282 | # Forward is the one with positive Poynting vector 283 | # Poynting vector is Re[n cos(theta)] for s-polarization or 284 | # Re[n cos(theta*)] for p-polarization, but it turns out they're consistent 285 | # so I'll just assume s then check both below 286 | answer = (~(abs(ncostheta.imag) > 100 * EPSILON)) * (ncostheta.real > 0) 287 | 288 | # answer = (~(abs(ncostheta.imag) > 100 * EPSILON)) * (ncostheta.real > 0) 289 | 290 | # Case Im(n) < 0 291 | assert (ncostheta.imag > -100 * EPSILON)[answer].all(), error_string 292 | 293 | # Case Re(n) < 0 294 | assert (ncostheta.real > -100 * EPSILON)[answer].all(), error_string 295 | assert ((n * torch.cos(torch.conj(theta))).real > -100 * EPSILON)[answer].all(), error_string 296 | 297 | assert (ncostheta.imag < 100 * EPSILON)[~answer].all(), error_string 298 | assert (ncostheta.real < 100 * EPSILON)[~answer].all(), error_string 299 | assert ((n * torch.cos(torch.conj(theta))).real < 100 * EPSILON)[~answer].all(), error_string 300 | answer = (~answer).clone().detach().type(torch.float) 301 | 302 | # for cross checking of the answer 303 | # answer_tmm = torch.empty_like(answer, dtype=torch.bool) 304 | # for i, _ in enumerate(answer_tmm): 305 | # for j, _ in enumerate(answer_tmm[i]): 306 | # for k, _ in enumerate(answer_tmm[i,j]): 307 | 308 | # m, t = n[i,0,k].numpy(), theta[i,j,k].numpy() 309 | # assert m.real * m.imag >= 0, ("For materials with gain, it's ambiguous which " 310 | # "beam is incoming vs outgoing. See " 311 | # "https://arxiv.org/abs/1603.02720 Appendix C.\n" 312 | # "n: " + str(m) + " angle: " + str(t)) 313 | # ncostheta2 = m * np.cos(t) 314 | # if abs(ncostheta2.imag) > 100 * EPSILON: 315 | # # Either evanescent decay or lossy medium. Either way, the one that 316 | # # decays is the forward-moving wave 317 | # answer2 = (ncostheta2.imag > 0) 318 | # else: 319 | # # Forward is the one with positive Poynting vector 320 | # # Poynting vector is Re[n cos(theta)] for s-polarization or 321 | # # Re[n cos(theta*)] for p-polarization, but it turns out they're consistent 322 | # # so I'll just assume s then check both below 323 | # answer2 = (ncostheta2.real > 0) 324 | # # convert from numpy boolean to the normal Python boolean 325 | # answer2 = bool(answer2) 326 | # # double-check the answer ... can't be too careful! 327 | # error_string = ("It's not clear which beam is incoming vs outgoing. Weird" 328 | # " index maybe?\n" 329 | # "n: " + str(m) + " angle: " + str(t)) 330 | # if answer2 is True: 331 | # assert ncostheta2.imag > -100 * EPSILON, error_string 332 | # assert ncostheta2.real > -100 * EPSILON, error_string 333 | # assert (m * np.cos(t.conjugate())).real > -100 * EPSILON, error_string 334 | # else: 335 | # assert ncostheta2.imag < 100 * EPSILON, error_string 336 | # assert ncostheta2.real < 100 * EPSILON, error_string 337 | # assert (m * np.cos(t.conjugate())).real < 100 * EPSILON, error_string 338 | 339 | # answer_tmm[i,j,k] = answer2 340 | 341 | # torch.testing.assert_close((~answer_tmm).type(torch.float), answer) 342 | 343 | return answer 344 | 345 | def is_forward_angle(n, theta): 346 | """ 347 | if a wave is traveling at angle theta from normal in a medium with index n, 348 | calculate whether or not this is the forward-traveling wave (i.e., the one 349 | going from front to back of the stack, like the incoming or outgoing waves, 350 | but unlike the reflected wave). For real n & theta, the criterion is simply 351 | -pi/2 < theta < pi/2, but for complex n & theta, it's more complicated. 352 | See https://arxiv.org/abs/1603.02720 appendix D. If theta is the forward 353 | angle, then (pi-theta) is the backward angle and vice-versa. 354 | """ 355 | n = n.clone().detach().to(torch.cfloat) # torch.tensor(n, dtype=torch.cfloat) 356 | assert torch.all(n.real * n.imag >= 0), ("For materials with gain, it's ambiguous which " 357 | "beam is incoming vs outgoing. See " 358 | "https://arxiv.org/abs/1603.02720 Appendix C.\n" 359 | "n: " + str(n) + " angle: " + str(theta)) 360 | # assert n.dtype is not complex, ("For materials with gain, it's ambiguous which " 361 | # "beam is incoming vs outgoing. See " 362 | # "https://arxiv.org/abs/1603.02720 Appendix C.\n" 363 | # "n: " + str(n) + " angle: " + str(theta)) 364 | 365 | ncostheta = n * torch.cos(theta) 366 | ncostheta = ncostheta.clone().detach().to(torch.cfloat) # torch.tensor(ncostheta, dtype=torch.cfloat) 367 | if torch.all(abs(ncostheta.imag) > 100 * EPSILON): 368 | # Either evanescent decay or lossy medium. Either way, the one that 369 | # decays is the forward-moving wave 370 | answer = (ncostheta.imag > 0) 371 | else: 372 | # Forward is the one with positive Poynting vector 373 | # Poynting vector is Re[n cos(theta)] for s-polarization or 374 | # Re[n cos(theta*)] for p-polarization, but it turns out they're consistent 375 | # so I'll just assume s then check both below 376 | answer = torch.any((ncostheta.real > 0)) 377 | # convert from numpy boolean to the normal Python boolean 378 | answer = bool(answer) 379 | # double-check the answer ... can't be too careful! 380 | error_string = ("It's not clear which beam is incoming vs outgoing. Weird" 381 | " index maybe?\n" 382 | "n: " + str(n) + " angle: " + str(theta)) 383 | if answer is True: 384 | assert torch.all(ncostheta.imag > -100 * EPSILON), error_string 385 | assert torch.all(ncostheta.real > -100 * EPSILON), error_string 386 | assert torch.all((n * torch.cos(theta.conj())).real > -100 * EPSILON), error_string 387 | else: 388 | assert torch.all(ncostheta.imag < 100 * EPSILON), error_string 389 | assert torch.all(ncostheta.real < 100 * EPSILON), error_string 390 | assert torch.all((n * torch.cos(theta.conjugate())).real < 100 * EPSILON), error_string 391 | return answer 392 | 393 | def interface_r_vec(polarization, n_i, n_f, th_i, th_f): 394 | """ 395 | reflection amplitude (from Fresnel equations) 396 | polarization is either "s" or "p" for polarization 397 | n_i, n_f are (complex) refractive index for incident and final 398 | th_i, th_f are (complex) propegation angle for incident and final 399 | (in radians, where 0=normal). "th" stands for "theta". 400 | """ 401 | if polarization == 's': 402 | ni_thi = torch.einsum('sij,skij->skji', n_i, torch.cos(th_i)) 403 | nf_thf = torch.einsum('sij,skij->skji', n_f, torch.cos(th_f)) 404 | return (ni_thi - nf_thf) / (ni_thi + nf_thf) 405 | elif polarization == 'p': 406 | nf_thi = torch.einsum('sij,skij->skji', n_f, torch.cos(th_i)) 407 | ni_thf = torch.einsum('sij,skij->skji', n_i, torch.cos(th_f)) 408 | return (nf_thi - ni_thf) / (nf_thi + ni_thf) 409 | else: 410 | raise ValueError("Polarization must be 's' or 'p'") 411 | 412 | def interface_t_vec(polarization, n_i, n_f, th_i, th_f): 413 | """ 414 | transmission amplitude (frem Fresnel equations) 415 | polarization is either "s" or "p" for polarization 416 | n_i, n_f are (complex) refractive index for incident and final 417 | th_i, th_f are (complex) propegation angle for incident and final 418 | (in radians, where 0=normal). "th" stands for "theta". 419 | """ 420 | if polarization == 's': 421 | ni_thi = torch.einsum('sij,skij->skji', n_i, torch.cos(th_i)) 422 | nf_thf = torch.einsum('sij,skij->skji', n_f, torch.cos(th_f)) 423 | return 2 * ni_thi / (ni_thi + nf_thf) 424 | elif polarization == 'p': 425 | nf_thi = torch.einsum('sij,skij->skji', n_f, torch.cos(th_i)) 426 | ni_thf = torch.einsum('sij,skij->skji', n_i, torch.cos(th_f)) 427 | ni_thi = torch.einsum('sij,skij->skji', n_i, torch.cos(th_i)) 428 | return 2 * ni_thi / (nf_thi + ni_thf) 429 | else: 430 | raise ValueError("Polarization must be 's' or 'p'") 431 | 432 | def R_from_r_vec(r): 433 | """ 434 | Calculate reflected power R, starting with reflection amplitude r. 435 | """ 436 | return abs(r) ** 2 437 | 438 | def T_from_t_vec(pol, t, n_i, n_f, th_i, th_f): 439 | """ 440 | Calculate transmitted power T, starting with transmission amplitude t. 441 | 442 | Parameters: 443 | ----------- 444 | pol : str 445 | polarization, either 's' or 'p' 446 | t : torch.Tensor 447 | transmission coefficients. Expects shape [] 448 | 449 | n_i, n_f are refractive indices of incident and final medium. 450 | th_i, th_f are (complex) propagation angles through incident & final medium 451 | (in radians, where 0=normal). "th" stands for "theta". 452 | In the case that n_i, n_f, th_i, th_f are real, formulas simplify to 453 | T=|t|^2 * (n_f cos(th_f)) / (n_i cos(th_i)). 454 | See manual for discussion of formulas 455 | """ 456 | 457 | if pol == 's': 458 | ni_thi = torch.real(torch.cos(th_i) * n_i.unsqueeze(1)) 459 | nf_thf = torch.real(torch.cos(th_f) * n_f.unsqueeze(1)) 460 | return (abs(t ** 2) * ((nf_thf) / (ni_thi))) 461 | 462 | elif pol == 'p': 463 | ni_thi = torch.real(torch.conj(torch.cos(th_i)) * n_i.unsqueeze(1)) 464 | nf_thf = torch.real(torch.conj(torch.cos(th_f)) * n_f.unsqueeze(1)) 465 | return (abs(t ** 2) * ((nf_thf) / (ni_thi))) 466 | 467 | else: 468 | raise ValueError("Polarization must be 's' or 'p'") 469 | 470 | def converter(data:Union[np.ndarray, torch.Tensor], device:str) -> torch.Tensor: 471 | ''' 472 | Checks the datatype of data to torch.tensor and moves the tensor to the device. 473 | 474 | Parameters: 475 | ----------- 476 | data : array_like 477 | data that should be converted to torch.Tensor 478 | device : str 479 | either 'cpu' or 'cuda' 480 | ''' 481 | if type(data) is not torch.Tensor: 482 | if type(data) is np.ndarray: 483 | data = torch.from_numpy(data.copy()) 484 | else: 485 | raise ValueError('At least one of the inputs (i.e. N, Theta, ...) is not of type numpy.array or torch.Tensor!') 486 | return data.type(torch.complex128).to(device) 487 | 488 | def numpy_converter(data:torch.Tensor)->np.ndarray: 489 | data = data.detach().cpu().numpy() 490 | return data 491 | 492 | def check_datatype(N, T, lambda_vacuum, Theta): 493 | assert type(N) == type(T) == type(lambda_vacuum) == type(Theta), ValueError('All inputs (i.e. N, Theta, ...) must be of the same data type, i.e. numpy.ndarray or torch.Tensor!') 494 | return type(N) 495 | 496 | def check_inputs(N, T, lambda_vacuum, theta): 497 | # check the dimensionalities of N: 498 | assert N.ndim == 3, 'N is not of shape [S x L x W] (3d), as it is of dimension ' + str(N.ndim) 499 | # check the dimensionalities of T: 500 | assert T.ndim == 2, 'T is not of shape [S x L] (2d), as it is of dimension ' + str(T.ndim) 501 | assert T.shape[0] == N.shape[0], 'The number of thin-films (first dimension) of N and T must coincide, \ 502 | \nfound N.shape=' + str(N.shape) + ' and T.shape=' + str(T.shape) + ' instead!' 503 | assert T.shape[1] == N.shape[1], 'The number of thin-film layers (second dimension) of N and T must coincide, \ 504 | \nfound N.shape=' + str(N.shape) + ' and T.shape=' + str(T.shape) + ' instead!' 505 | # check the dimensionality of Theta: 506 | assert theta.ndim == 1, 'Theta is not of shape [A] (1d), as it is of dimension ' + str(theta.ndim) 507 | # check the dimensionality of lambda_vacuum: 508 | assert lambda_vacuum.ndim == 1, 'lambda_vacuum is not of shape [W] (1d), as it is of dimension ' + str(lambda_vacuum.ndim) 509 | assert N.shape[-1] == lambda_vacuum.shape[0], 'The last dimension of N must coincide with the dimension of lambda_vacuum (W),\nfound N.shape[-1]=' + str(N.shape[-1]) + ' and lambda_vacuum.shape[0]=' + str(lambda_vacuum.shape[0]) + ' instead!' 510 | # check well defined property of refractive indicies for the first and last layer: 511 | answer = torch.all(abs((torch.einsum('ij,k->ijk', N[:, 0], torch.sin(theta)).imag)) < np.finfo(float).eps) 512 | assert answer, 'Non well-defined refractive indicies detected for first layer, check index ' + torch.argwhere( 513 | abs((torch.einsum('ij,k->ijk', N[:, 0], torch.sin(theta)).imag)) > np.finfo(float).eps 514 | ) 515 | 516 | 517 | 518 | 519 | 520 | def make_2x2_tensor(a, b, c, d, dtype=float): 521 | """ 522 | Makes a 2x2 numpy array of [[a,b],[c,d]] 523 | Same as "numpy.array([[a,b],[c,d]], dtype=float)", but ten times faster 524 | """ 525 | my_array = torch.empty((2, 2), dtype=dtype) 526 | my_array[0, 0] = a 527 | my_array[0, 1] = b 528 | my_array[1, 0] = c 529 | my_array[1, 1] = d 530 | return my_array 531 | --------------------------------------------------------------------------------