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