├── .gitignore ├── LICENSE.txt ├── README.md ├── fdfdpy ├── __init__.py ├── constants.py ├── derivatives.py ├── linalg.py ├── nonlinear_solvers.py ├── nonlinearity.py ├── plot.py ├── pml.py ├── simulation.py └── source │ ├── __init__.py │ └── mode.py ├── img └── dipole_dielectric_field.png ├── notebooks ├── Examples.ipynb └── Examples_nonlinear.ipynb ├── setup.py └── tests ├── __init__.py ├── test_chi3.py ├── test_flux.py ├── test_linear.py ├── test_modes.py ├── test_nonlinear.py ├── test_nonlinear_solvers.py └── test_simulation.py /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | .DS_Store 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # IPython 80 | profile_default/ 81 | ipython_config.py 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # celery beat schedule file 87 | celerybeat-schedule 88 | 89 | # SageMath parsed files 90 | *.sage.py 91 | 92 | # Environments 93 | .env 94 | .venv 95 | env/ 96 | venv/ 97 | ENV/ 98 | env.bak/ 99 | venv.bak/ 100 | 101 | # Spyder project settings 102 | .spyderproject 103 | .spyproject 104 | 105 | # Rope project settings 106 | .ropeproject 107 | 108 | # mkdocs documentation 109 | /site 110 | 111 | # mypy 112 | .mypy_cache/ 113 | .dmypy.json 114 | dmypy.json 115 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Fan Group 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 | ![](img/dipole_dielectric_field.png) 2 | 3 | # fdfdpy 4 | 5 | This is a pure Python implementation of the finite difference frequency domain (FDFD) method. It makes use of scipy, numpy, matplotlib, and the MKL Pardiso solver. fdfdpy currently supports 2D geometries 6 | 7 | ## Installation 8 | 9 | python setup.py install 10 | 11 | ## Examples 12 | 13 | See the ipython notebooks in `notebooks`. 14 | 15 | ## Unit Tests 16 | 17 | Some basic tests are included in `tests/` 18 | 19 | To run an example test, `tests/test_nonlinear_solvers.py`, either call 20 | 21 | python -m unittest tests/test_nonlinear_solvers.py 22 | 23 | or 24 | 25 | python tests/test_nonlinear_solvers.py 26 | 27 | ## Structure 28 | 29 | ### Initialization 30 | 31 | The `Simulation` class is initialized as 32 | 33 | from fdfdpy import Simulation 34 | simulation = Simulation(omega, eps_r, dl, NPML, pol, L0) 35 | 36 | - `omega` : the angular frequency in units of` 2 pi / seconds` 37 | - `eps_r` : a numpy array specifying the relative permittivity distribution 38 | - `dl` : the spatial grid size in units of `L0` 39 | - `NPML` : defines number of PML grids `[# on x borders, # on y borders]` 40 | - `pol` : polarization, one of `{'Hz','Ez'}` where `z` is the transverse field. 41 | - `L0` : (optional) simulation length scale, default is 1e-6 meters (one micron) 42 | 43 | Creating a new Fdfd object solves for: 44 | 45 | - `xrange` : defines spatial domain in x [left-most position, right-most position] in units of `L0` 46 | - `yrange` : defines spatial domain in y [bottom-most position, top-most position] in units of `L0` 47 | - `A` : the Maxwell operator, which is used later to solve for the E&M fields. 48 | - `derivs` : dictionary storing the derivative operators. 49 | 50 | It also creates a relative permeability, `mu_r`, as `numpy.ones(eps_r.shape)` and a source `src` as `numpy.zeros(eps_r.shape)`. 51 | 52 | ### Adding sources is exciting! 53 | 54 | Sources can be added to the simulation either by manually editing the 2D src array inside of the simulation object, 55 | 56 | simulation.src[10,20:30] = 1 57 | 58 | or by adding modal sources, which are defined as planes within the 2D domain which launch a mode in their normal direction. Modal source definitions can be added to the simulation by 59 | 60 | simulation.add_mode(neff, direction, center, width) 61 | simulation.setup_modes() 62 | 63 | - `neff` : defines the effective index of the mode; this will be used as the eigenvalue guess 64 | - `direction` : defines the normal direction of the plane, should be either 'x' or 'y' 65 | - `center` : defines the center coordinates for the plane in cell coordinates [xc, yc] 66 | - `width` : defines the width of the plane in number of cells 67 | 68 | Note that `simulation.setup_modes()` must always be called after adding mode(s) in order to populate `simulation.src`. 69 | 70 | ### Solving for the electromagnetic fields 71 | 72 | Now, we have everything we need to solve the system for the electromagnetic fields, by running 73 | 74 | fields = simulation.solve_fields(timing=False) 75 | 76 | `simulation.src` is proportional to either the `Jz` or `Mz` source term, depending on whether `pol` is set to `'Ez'` or `'Hz'`, respectively. 77 | 78 | `fields` is a tuple containing `(Ex, Ey, Hz)` or `(Hx, Hy, Ez)` depending on the polarization. 79 | 80 | ### Setting a new permittivity 81 | 82 | If you want to change the permittivity distribution, reassigning `eps_r` 83 | 84 | simulation.eps_r = eps_new 85 | 86 | will automatically solve for a new system matrix with the new permittivity distribution. Note that `simulation.setup_modes()` should also be called if the permittivity changed within the plane of any of the modal sources. <- I'll make this happen automatically later -T 87 | 88 | ### Plotting 89 | 90 | Primary fields (Hz/Ez) can be visualized using the included helper functions: 91 | 92 | simulation.plt_re(outline=True, cbar=True) 93 | simulation.plt_abs(outline=True, cbar=True, vmax=None) 94 | 95 | These optionally outline the permittivity with contours and can be supplied with a matplotlib axis handle to plot into. 96 | 97 | ### To Do 98 | 99 | #### Whenever 100 | - [ ] xrange, yrange labels on plots. 101 | - [ ] set modal source amplitude (and normalization) 102 | - [ ] Add ability to run local jupyter notebooks running FDFD on parallel from server. 103 | - [ ] Save the factorization of `A` in the `Fdfd` object to be reused later if one has the same `A` but a different `b`. 104 | - [ ] Allow the source term to have `(Jx, Jy, Jz, Mx, My, Mz)`, which would be useful for adjoint stuff where the source is not necessarily along the `z` direction. 105 | -------------------------------------------------------------------------------- /fdfdpy/__init__.py: -------------------------------------------------------------------------------- 1 | # This line makes it possible to load Simulation object directly as 2 | # `from fdfdpy import Simulation` 3 | from .simulation import Simulation 4 | 5 | # used for setup.py 6 | name = "fdfdpy" -------------------------------------------------------------------------------- /fdfdpy/constants.py: -------------------------------------------------------------------------------- 1 | from numpy import sqrt 2 | 3 | EPSILON_0 = 8.85418782e-12 4 | MU_0 = 1.25663706e-6 5 | C_0 = sqrt(1/EPSILON_0/MU_0) 6 | ETA_0 = sqrt(MU_0/EPSILON_0) 7 | 8 | DEFAULT_MATRIX_FORMAT = 'csr' 9 | DEFAULT_SOLVER = 'pardiso' 10 | DEFAULT_LENGTH_SCALE = 1e-6 # microns 11 | -------------------------------------------------------------------------------- /fdfdpy/derivatives.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | 4 | from fdfdpy.constants import DEFAULT_MATRIX_FORMAT 5 | 6 | 7 | def createDws(w, s, dL, N, matrix_format=DEFAULT_MATRIX_FORMAT): 8 | # creates the derivative matrices 9 | # NOTE: python uses C ordering rather than Fortran ordering. Therefore the 10 | # derivative operators are constructed slightly differently than in MATLAB 11 | 12 | Nx = N[0] 13 | dx = dL[0] 14 | if len(N) is not 1: 15 | Ny = N[1] 16 | dy = dL[1] 17 | else: 18 | Ny = 1 19 | dy = np.inf 20 | if w is 'x': 21 | if s is 'f': 22 | dxf = sp.diags([-1, 1, 1], [0, 1, -Nx+1], shape=(Nx, Nx)) 23 | Dws = 1/dx*sp.kron(dxf, sp.eye(Ny), format=matrix_format) 24 | else: 25 | dxb = sp.diags([1, -1, -1], [0, -1, Nx-1], shape=(Nx, Nx)) 26 | Dws = 1/dx*sp.kron(dxb, sp.eye(Ny), format=matrix_format) 27 | if w is 'y': 28 | if s is 'f': 29 | dyf = sp.diags([-1, 1, 1], [0, 1, -Ny+1], shape=(Ny, Ny)) 30 | Dws = 1/dy*sp.kron(sp.eye(Nx), dyf, format=matrix_format) 31 | else: 32 | dyb = sp.diags([1, -1, -1], [0, -1, Ny-1], shape=(Ny, Ny)) 33 | Dws = 1/dy*sp.kron(sp.eye(Nx), dyb, format=matrix_format) 34 | return Dws 35 | 36 | 37 | def unpack_derivs(derivs): 38 | # takes derivs dictionary and returns tuple for convenience 39 | 40 | Dyb = derivs['Dyb'] 41 | Dxb = derivs['Dxb'] 42 | Dxf = derivs['Dxf'] 43 | Dyf = derivs['Dyf'] 44 | return (Dyb, Dxb, Dxf, Dyf) 45 | -------------------------------------------------------------------------------- /fdfdpy/linalg.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | import scipy.sparse.linalg as spl 4 | from pyMKL import pardisoSolver 5 | from time import time 6 | 7 | from fdfdpy.constants import DEFAULT_MATRIX_FORMAT, DEFAULT_SOLVER 8 | from fdfdpy.constants import EPSILON_0, MU_0 9 | from fdfdpy.pml import S_create 10 | from fdfdpy.derivatives import createDws 11 | 12 | from pyMKL import pardisoSolver 13 | from time import time 14 | 15 | 16 | def grid_average(center_array, w): 17 | # computes values at cell edges 18 | 19 | xy = {'x': 0, 'y': 1} 20 | center_shifted = np.roll(center_array, 1, axis=xy[w]) 21 | avg_array = (center_shifted+center_array)/2 22 | return avg_array 23 | 24 | 25 | def dL(N, xrange, yrange=None): 26 | # solves for the grid spacing 27 | 28 | if yrange is None: 29 | L = np.array([np.diff(xrange)[0]]) # Simulation domain lengths 30 | else: 31 | L = np.array([np.diff(xrange)[0], 32 | np.diff(yrange)[0]]) # Simulation domain lengths 33 | return L/N 34 | 35 | 36 | def is_equal(matrix1, matrix2): 37 | # checks if two sparse matrices are equal 38 | return (matrix1 != matrix2).nnz == 0 39 | 40 | 41 | def construct_A(omega, xrange, yrange, eps_r, NPML, pol, L0, 42 | averaging=True, 43 | timing=False, 44 | matrix_format=DEFAULT_MATRIX_FORMAT): 45 | # makes the A matrix 46 | N = np.asarray(eps_r.shape) # Number of mesh cells 47 | M = np.prod(N) # Number of unknowns 48 | 49 | EPSILON_0_ = EPSILON_0*L0 50 | MU_0_ = MU_0*L0 51 | 52 | if pol == 'Ez': 53 | vector_eps_z = EPSILON_0_*eps_r.reshape((-1,)) 54 | T_eps_z = sp.spdiags(vector_eps_z, 0, M, M, format=matrix_format) 55 | 56 | (Sxf, Sxb, Syf, Syb) = S_create(omega, L0, N, NPML, xrange, yrange, matrix_format=matrix_format) 57 | 58 | # Construct derivate matrices 59 | Dyb = Syb.dot(createDws('y', 'b', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 60 | Dxb = Sxb.dot(createDws('x', 'b', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 61 | Dxf = Sxf.dot(createDws('x', 'f', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 62 | Dyf = Syf.dot(createDws('y', 'f', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 63 | 64 | A = (Dxf*1/MU_0_).dot(Dxb) \ 65 | + (Dyf*1/MU_0_).dot(Dyb) \ 66 | + omega**2*T_eps_z 67 | # A = A / (omega**2*EPSILON_0) # normalize A to be unitless. (note, this isn't in original fdfdpy) 68 | 69 | elif pol == 'Hz': 70 | if averaging: 71 | vector_eps_x = grid_average(EPSILON_0_*eps_r, 'x').reshape((-1,)) 72 | vector_eps_y = grid_average(EPSILON_0_*eps_r, 'y').reshape((-1,)) 73 | else: 74 | vector_eps_x = EPSILON_0_*eps_r.reshape((-1,)) 75 | vector_eps_y = EPSILON_0_*eps_r.reshape((-1,)) 76 | 77 | # Setup the T_eps_x, T_eps_y, T_eps_x_inv, and T_eps_y_inv matrices 78 | T_eps_x = sp.spdiags(vector_eps_x, 0, M, M, format=matrix_format) 79 | T_eps_y = sp.spdiags(vector_eps_y, 0, M, M, format=matrix_format) 80 | T_eps_x_inv = sp.spdiags(1/vector_eps_x, 0, M, M, format=matrix_format) 81 | T_eps_y_inv = sp.spdiags(1/vector_eps_y, 0, M, M, format=matrix_format) 82 | 83 | (Sxf, Sxb, Syf, Syb) = S_create(omega, L0, N, NPML, xrange, yrange, matrix_format=matrix_format) 84 | 85 | # Construct derivate matrices 86 | Dyb = Syb.dot(createDws('y', 'b', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 87 | Dxb = Sxb.dot(createDws('x', 'b', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 88 | Dxf = Sxf.dot(createDws('x', 'f', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 89 | Dyf = Syf.dot(createDws('y', 'f', dL(N, xrange, yrange), N, matrix_format=matrix_format)) 90 | 91 | A = Dxf.dot(T_eps_x_inv).dot(Dxb) \ 92 | + Dyf.dot(T_eps_y_inv).dot(Dyb) \ 93 | + omega**2*MU_0_*eye(M) 94 | 95 | # A = A / (omega**2*MU_0) # normalize A to be unitless. (note, this isn't in original fdfdpy) 96 | 97 | else: 98 | raise ValueError("something went wrong and pol is not one of Ez, Hz, instead was given {}".format(pol)) 99 | 100 | derivs = { 101 | 'Dyb' : Dyb, 102 | 'Dxb' : Dxb, 103 | 'Dxf' : Dxf, 104 | 'Dyf' : Dyf 105 | } 106 | 107 | return (A, derivs) 108 | 109 | 110 | def solver_eigs(A, Neigs, guess_value=0, guess_vector=None, timing=False): 111 | # solves for the eigenmodes of A 112 | 113 | if timing: 114 | start = time() 115 | (values, vectors) = spl.eigs(A, k=Neigs, sigma=guess_value, v0=guess_vector, which='LM') 116 | if timing: 117 | end = time() 118 | print('Elapsed time for eigs() is %.4f secs' % (end - start)) 119 | return (values, vectors) 120 | 121 | 122 | def solver_direct(A, b, timing=False, solver=DEFAULT_SOLVER): 123 | # solves linear system of equations 124 | 125 | b = b.astype(np.complex128) 126 | b = b.reshape((-1,)) 127 | 128 | if not b.any(): 129 | return np.zeros(b.shape) 130 | 131 | if timing: 132 | t = time() 133 | 134 | if solver.lower() == 'pardiso': 135 | pSolve = pardisoSolver(A, mtype=13) # Matrix is complex unsymmetric due to SC-PML 136 | pSolve.factor() 137 | x = pSolve.solve(b) 138 | pSolve.clear() 139 | 140 | elif solver.lower() == 'scipy': 141 | x = spl.spsolve(A, b) 142 | 143 | else: 144 | raise ValueError('Invalid solver choice: {}, options are pardiso or scipy'.format(str(solver))) 145 | 146 | if timing: 147 | print('Linear system solve took {:.2f} seconds'.format(time()-t)) 148 | 149 | return x 150 | 151 | 152 | def solver_complex2real(A11, A12, b, timing=False, solver=DEFAULT_SOLVER): 153 | # solves linear system of equations [A11, A12; A21*, A22*]*[x; x*] = [b; b*] 154 | 155 | b = b.astype(np.complex128) 156 | b = b.reshape((-1,)) 157 | N = b.size 158 | 159 | if not b.any(): 160 | return zeros(b.shape) 161 | 162 | b_re = np.real(b).astype(np.float64) 163 | b_im = np.imag(b).astype(np.float64) 164 | 165 | Areal = sp.vstack((sp.hstack((np.real(A11) + np.real(A12), - np.imag(A11) + np.imag(A12))), 166 | sp.hstack((np.imag(A11) + np.imag(A12), np.real(A11) - np.real(A12))))) 167 | 168 | if timing: 169 | t = time() 170 | 171 | if solver.lower() == 'pardiso': 172 | pSolve = pardisoSolver(Areal, mtype=11) # Matrix is real unsymmetric 173 | pSolve.factor() 174 | x = pSolve.solve(np.hstack((b_re, b_im))) 175 | pSolve.clear() 176 | 177 | elif solver.lower() == 'scipy': 178 | x = spsolve(Areal, np.hstack((b_re, b_im))) 179 | 180 | else: 181 | raise ValueError('Invalid solver choice: {}, options are pardiso or scipy'.format(str(solver))) 182 | 183 | if timing: 184 | print('Linear system solve took {:.2f} seconds'.format(time()-t)) 185 | 186 | return (x[:N] + 1j*x[N:2*N]) 187 | -------------------------------------------------------------------------------- /fdfdpy/nonlinear_solvers.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import numpy.linalg as la 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as spl 5 | from copy import deepcopy 6 | 7 | from fdfdpy.linalg import grid_average, solver_direct, solver_complex2real 8 | from fdfdpy.derivatives import unpack_derivs 9 | from fdfdpy.constants import (DEFAULT_LENGTH_SCALE, DEFAULT_MATRIX_FORMAT, 10 | DEFAULT_SOLVER, EPSILON_0, MU_0) 11 | 12 | 13 | def born_solve(simulation, 14 | Estart=None, conv_threshold=1e-10, max_num_iter=50, 15 | averaging=True): 16 | # solves for the nonlinear fields 17 | 18 | # Stores convergence parameters 19 | conv_array = np.zeros((max_num_iter, 1)) 20 | 21 | if simulation.pol == 'Ez': 22 | # Defne the starting field for the simulation 23 | if Estart is None: 24 | if simulation.fields['Ez'] is None: 25 | (_, _, Ez) = simulation.solve_fields() 26 | else: 27 | Ez = deepcopy(simulation.fields['Ez']) 28 | else: 29 | Ez = Estart 30 | 31 | # Solve iteratively 32 | for istep in range(max_num_iter): 33 | 34 | Eprev = Ez 35 | 36 | # set new permittivity 37 | simulation.compute_nl(Eprev) 38 | 39 | (Hx, Hy, Ez) = simulation.solve_fields(include_nl=True) 40 | 41 | # get convergence and break 42 | convergence = la.norm(Ez - Eprev)/la.norm(Ez) 43 | conv_array[istep] = convergence 44 | 45 | # if below threshold, break and return 46 | if convergence < conv_threshold: 47 | break 48 | 49 | if convergence > conv_threshold: 50 | print("the simulation did not converge, reached {}".format(convergence)) 51 | return (Hx, Hy, Ez, conv_array) 52 | 53 | else: 54 | raise ValueError('Invalid polarization: {}'.format(str(self.pol))) 55 | 56 | 57 | def newton_solve(simulation, 58 | Estart=None, conv_threshold=1e-10, max_num_iter=50, 59 | averaging=True, solver=DEFAULT_SOLVER, jac_solver='c2r', 60 | matrix_format=DEFAULT_MATRIX_FORMAT): 61 | # solves for the nonlinear fields using Newton's method 62 | 63 | # Stores convergence parameters 64 | conv_array = np.zeros((max_num_iter, 1)) 65 | 66 | # num. columns and rows of A 67 | Nbig = simulation.Nx*simulation.Ny 68 | 69 | if simulation.pol == 'Ez': 70 | # Defne the starting field for the simulation 71 | if Estart is None: 72 | if simulation.fields['Ez'] is None: 73 | (_, _, Ez) = simulation.solve_fields() 74 | else: 75 | Ez = deepcopy(simulation.fields['Ez']) 76 | else: 77 | Ez = Estart 78 | 79 | # Solve iteratively 80 | for istep in range(max_num_iter): 81 | Eprev = Ez 82 | 83 | (fx, Jac11, Jac12) = nl_eq_and_jac(simulation, Ez=Eprev, 84 | matrix_format=matrix_format) 85 | 86 | # Note: Newton's method is defined as a linear problem to avoid inverting the Jacobian 87 | # Namely, J*(x_n - x_{n-1}) = -f(x_{n-1}), where J = df/dx(x_{n-1}) 88 | 89 | Ediff = solver_complex2real(Jac11, Jac12, fx, 90 | solver=solver, timing=False) 91 | # Abig = sp.sp_vstack((sp.sp_hstack((Jac11, Jac12)), \ 92 | # sp.sp_hstack((np.conj(Jac12), np.conj(Jac11))))) 93 | # Ediff = solver_direct(Abig, np.vstack((fx, np.conj(fx)))) 94 | 95 | Ez = Eprev - Ediff[range(Nbig)].reshape(simulation.Nx, simulation.Ny) 96 | 97 | # get convergence and break 98 | convergence = la.norm(Ez - Eprev)/la.norm(Ez) 99 | conv_array[istep] = convergence 100 | 101 | # if below threshold, break and return 102 | if convergence < conv_threshold: 103 | break 104 | 105 | # Solve the fdfd problem with the final eps_nl 106 | simulation.compute_nl(Ez) 107 | (Hx, Hy, Ez) = simulation.solve_fields(include_nl=True) 108 | 109 | if convergence > conv_threshold: 110 | print("the simulation did not converge, reached {}".format(convergence)) 111 | 112 | return (Hx, Hy, Ez, conv_array) 113 | 114 | else: 115 | raise ValueError('Invalid polarization: {}'.format(str(self.pol))) 116 | 117 | def nl_eq_and_jac(simulation, 118 | averaging=True, Ex=None, Ey=None, Ez=None, compute_jac=True, 119 | matrix_format=DEFAULT_MATRIX_FORMAT): 120 | # Evaluates the nonlinear function f(E) that defines the problem to solve f(E) = 0, as well as the Jacobian df/dE 121 | # Could add a check that only Ez is None for Hz polarization and vice-versa 122 | 123 | omega = simulation.omega 124 | EPSILON_0_ = EPSILON_0*simulation.L0 125 | MU_0_ = MU_0*simulation.L0 126 | 127 | Nbig = simulation.Nx*simulation.Ny 128 | 129 | if simulation.pol == 'Ez': 130 | simulation.compute_nl(Ez) 131 | Anl = simulation.A + simulation.Anl 132 | fE = (Anl.dot(Ez.reshape(-1,)) - simulation.src.reshape(-1,)*1j*omega) 133 | 134 | # Make it explicitly a column vector 135 | fE = fE.reshape(Nbig, 1) 136 | 137 | if compute_jac: 138 | simulation.compute_nl(Ez) 139 | dAde = (simulation.dnl_de).reshape((-1,))*omega**2*EPSILON_0_ 140 | Jac11 = Anl + sp.spdiags(dAde*Ez.reshape((-1,)), 0, Nbig, Nbig, format=matrix_format) 141 | Jac12 = sp.spdiags(np.conj(dAde)*Ez.reshape((-1,)), 0, Nbig, Nbig, format=matrix_format) 142 | 143 | else: 144 | raise ValueError('Invalid polarization: {}'.format(str(self.pol))) 145 | 146 | if compute_jac: 147 | return (fE, Jac11, Jac12) 148 | else: 149 | return fE 150 | -------------------------------------------------------------------------------- /fdfdpy/nonlinearity.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from fdfdpy.linalg import * 4 | 5 | 6 | class Nonlinearity: 7 | 8 | def __init__(self, chi, nl_region, nl_type='kerr', eps_scale=False, eps_max=None): 9 | self.chi = chi 10 | self.nl_region = nl_region 11 | self.nl_type = nl_type 12 | self.eps_scale = eps_scale 13 | self.eps_max = eps_max 14 | self.eps_nl = [] 15 | self.dnl_de = [] 16 | self.dnl_deps = [] 17 | 18 | if self.nl_type == 'kerr': 19 | if self.eps_scale == True: 20 | if self.eps_max == None: 21 | raise AssertionError("Must provide eps_max when eps_scale is True") 22 | 23 | else: 24 | kerr_nonlinearity = lambda e, eps_r:3*chi*nl_region*np.square(np.abs(e))*((eps_r-1)/(eps_max - 1)) 25 | kerr_nl_de = lambda e, eps_r:3*chi*nl_region*np.conj(e)*((eps_r-1)/(eps_max - 1)) 26 | kerr_nl_deps = lambda e, eps_r:3*chi*nl_region*np.square(np.abs(e))*(1/(eps_max - 1)) 27 | 28 | else: 29 | kerr_nonlinearity = lambda e, eps_r:3*chi*nl_region*np.square(np.abs(e)) 30 | kerr_nl_de = lambda e, eps_r:3*chi*nl_region*np.conj(e) 31 | kerr_nl_deps = lambda e, eps_r:0 32 | self.eps_nl = kerr_nonlinearity 33 | self.dnl_de = kerr_nl_de 34 | self.dnl_deps = kerr_nl_deps 35 | 36 | else: 37 | raise AssertionError("Only 'kerr' type nonlinearity is supported") 38 | -------------------------------------------------------------------------------- /fdfdpy/plot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib as mpl 4 | 5 | 6 | def plt_base(field_val, outline_val, cmap, vmin, vmax, label, 7 | cbar=True, outline=None, ax=None): 8 | # Base plotting function for fields 9 | 10 | field_val = field_val.transpose() 11 | outline_val = outline_val.transpose() 12 | 13 | if ax is None: 14 | fig, ax = plt.subplots(1, constrained_layout=True) 15 | 16 | h = ax.imshow(field_val, cmap=cmap, vmin=vmin, vmax=vmax, origin='lower') 17 | 18 | if cbar: 19 | plt.colorbar(h, label=label, ax=ax) 20 | 21 | if outline: 22 | # Do black and white so we can see on both magma and RdBu 23 | ax.contour(outline_val, levels=2, linewidths=1.0, colors='w') 24 | ax.contour(outline_val, levels=2, linewidths=0.5, colors='k') 25 | 26 | ax.set_xticks([]) 27 | ax.set_yticks([]) 28 | 29 | return ax 30 | 31 | 32 | def plt_base_eps(field_val, outline_val, cmap, vmin, vmax, 33 | cbar=True, outline=None, ax=None): 34 | # Base plotting function for permittivity 35 | 36 | field_val = field_val.transpose() 37 | outline_val = outline_val.transpose() 38 | 39 | if ax is None: 40 | fig, ax = plt.subplots(1, constrained_layout=True) 41 | 42 | h = ax.imshow(field_val, cmap=cmap, vmin=vmin, vmax=vmax, origin='lower') 43 | 44 | if cbar: 45 | plt.colorbar(h, label='relative permittivity', ax=ax) 46 | 47 | if outline: 48 | # Do black and white so we can see on both magma and RdBu 49 | ax.contour(outline_val, levels=2, linewidths=1.0, colors='w') 50 | ax.contour(outline_val, levels=2, linewidths=0.5, colors='k') 51 | 52 | ax.set_xticks([]) 53 | ax.set_yticks([]) 54 | 55 | return ax 56 | 57 | 58 | def plt_base_ani(field_val, cbar=True, Nframes=40, interval=80): 59 | 60 | field_val = field_val.transpose() 61 | 62 | fig, ax = plt.subplots(1, constrained_layout=True) 63 | h = ax.imshow(np.zeros(field_val.shape).transpose(), origin='lower') 64 | 65 | ax.set_xticks([]) 66 | ax.set_yticks([]) 67 | 68 | def init(): 69 | vmax = np.abs(field_val).max() 70 | h.set_data(np.zeros(field_val.shape).transpose()) 71 | h.set_cmap('RdBu') 72 | h.set_clim(vmin=-vmax, vmax=+vmax) 73 | 74 | return (h,) 75 | 76 | def animate(i): 77 | fields = np.real(field_val*np.exp(1j*2*np.pi*i/(Nframes-1))) 78 | h.set_data(fields) 79 | return (h,) 80 | 81 | plt.close() 82 | return mpl.animation.FuncAnimation(fig, animate, init_func=init, 83 | frames=Nframes, interval=interval, 84 | blit=True) 85 | -------------------------------------------------------------------------------- /fdfdpy/pml.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | 4 | from fdfdpy.constants import ETA_0, EPSILON_0, DEFAULT_MATRIX_FORMAT 5 | 6 | 7 | def sig_w(l, dw, m=4, lnR=-12): 8 | # helper for S() 9 | 10 | sig_max = -(m+1)*lnR/(2*ETA_0*dw) 11 | return sig_max*(l/dw)**m 12 | 13 | 14 | def S(l, dw, omega, L0): 15 | # helper for create_sfactor() 16 | 17 | return 1 - 1j*sig_w(l, dw)/(omega*EPSILON_0*L0) 18 | 19 | 20 | def create_sfactor(wrange, L0, s, omega, Nw, Nw_pml): 21 | # used to help construct the S matrices for the PML creation 22 | 23 | sfactor_array = np.ones(Nw, dtype=np.complex128) 24 | if Nw_pml < 1: 25 | return sfactor_array 26 | hw = np.diff(wrange)[0]/Nw 27 | dw = Nw_pml*hw 28 | for i in range(0, Nw): 29 | if s is 'f': 30 | if i <= Nw_pml: 31 | sfactor_array[i] = S(hw * (Nw_pml - i + 0.5), dw, omega, L0) 32 | elif i > Nw - Nw_pml: 33 | sfactor_array[i] = S(hw * (i - (Nw - Nw_pml) - 0.5), dw, omega, L0) 34 | if s is 'b': 35 | if i <= Nw_pml: 36 | sfactor_array[i] = S(hw * (Nw_pml - i + 1), dw, omega, L0) 37 | elif i > Nw - Nw_pml: 38 | sfactor_array[i] = S(hw * (i - (Nw - Nw_pml) - 1), dw, omega, L0) 39 | return sfactor_array 40 | 41 | 42 | def S_create(omega, L0, N, Npml, xrange, 43 | yrange=None, matrix_format=DEFAULT_MATRIX_FORMAT): 44 | # creates S matrices for the PML creation 45 | 46 | M = np.prod(N) 47 | if np.isscalar(Npml): 48 | Npml = np.array([Npml]) 49 | if len(N) < 2: 50 | N = np.append(N, 1) 51 | Npml = np.append(Npml, 0) 52 | Nx = N[0] 53 | Nx_pml = Npml[0] 54 | Ny = N[1] 55 | Ny_pml = Npml[1] 56 | 57 | # Create the sfactor in each direction and for 'f' and 'b' 58 | s_vector_x_f = create_sfactor(xrange, L0, 'f', omega, Nx, Nx_pml) 59 | s_vector_x_b = create_sfactor(xrange, L0, 'b', omega, Nx, Nx_pml) 60 | s_vector_y_f = create_sfactor(yrange, L0, 'f', omega, Ny, Ny_pml) 61 | s_vector_y_b = create_sfactor(yrange, L0, 'b', omega, Ny, Ny_pml) 62 | 63 | # Fill the 2D space with layers of appropriate s-factors 64 | Sx_f_2D = np.zeros(N, dtype=np.complex128) 65 | Sx_b_2D = np.zeros(N, dtype=np.complex128) 66 | Sy_f_2D = np.zeros(N, dtype=np.complex128) 67 | Sy_b_2D = np.zeros(N, dtype=np.complex128) 68 | 69 | for i in range(0, Ny): 70 | Sx_f_2D[:, i] = 1/s_vector_x_f 71 | Sx_b_2D[:, i] = 1/s_vector_x_b 72 | 73 | for i in range(0, Nx): 74 | Sy_f_2D[i, :] = 1/s_vector_y_f 75 | Sy_b_2D[i, :] = 1/s_vector_y_b 76 | 77 | # Reshape the 2D s-factors into a 1D s-array 78 | Sx_f_vec = Sx_f_2D.reshape((-1,)) 79 | Sx_b_vec = Sx_b_2D.reshape((-1,)) 80 | Sy_f_vec = Sy_f_2D.reshape((-1,)) 81 | Sy_b_vec = Sy_b_2D.reshape((-1,)) 82 | 83 | # Construct the 1D total s-array into a diagonal matrix 84 | Sx_f = sp.spdiags(Sx_f_vec, 0, M, M, format=matrix_format) 85 | Sx_b = sp.spdiags(Sx_b_vec, 0, M, M, format=matrix_format) 86 | Sy_f = sp.spdiags(Sy_f_vec, 0, M, M, format=matrix_format) 87 | Sy_b = sp.spdiags(Sy_b_vec, 0, M, M, format=matrix_format) 88 | 89 | return (Sx_f, Sx_b, Sy_f, Sy_b) 90 | -------------------------------------------------------------------------------- /fdfdpy/simulation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | from copy import deepcopy 4 | 5 | from fdfdpy.linalg import construct_A, solver_direct, grid_average 6 | from fdfdpy.derivatives import unpack_derivs 7 | from fdfdpy.plot import plt_base, plt_base_eps 8 | from fdfdpy.nonlinear_solvers import born_solve, newton_solve 9 | from fdfdpy.source.mode import mode 10 | from fdfdpy.nonlinearity import Nonlinearity 11 | from fdfdpy.constants import (DEFAULT_LENGTH_SCALE, DEFAULT_MATRIX_FORMAT, 12 | DEFAULT_SOLVER, EPSILON_0, MU_0) 13 | 14 | 15 | class Simulation: 16 | 17 | def __init__(self, omega, eps_r, dl, NPML, pol, L0=DEFAULT_LENGTH_SCALE): 18 | # initializes Fdfd object 19 | 20 | self.L0 = L0 21 | self.omega = float(omega) 22 | self.dl = float(dl) 23 | self.NPML = [int(n) for n in NPML] 24 | self.pol = pol 25 | 26 | self._check_inputs() 27 | 28 | (Nx, Ny) = eps_r.shape 29 | self.Nx = Nx 30 | self.Ny = Ny 31 | self.mu_r = np.ones((self.Nx, self.Ny)) 32 | self.src = np.zeros((self.Nx, self.Ny)) 33 | self.xrange = [0, float(Nx*self.dl)] 34 | self.yrange = [0, float(Ny*self.dl)] 35 | 36 | # construct the system matrix 37 | self.eps_r = eps_r 38 | 39 | self.modes = [] 40 | self.nonlinearity = [] 41 | self.eps_nl = np.zeros(eps_r.shape) 42 | self.dnl_de = np.zeros(eps_r.shape) 43 | self.dnl_deps = np.zeros(eps_r.shape) 44 | 45 | def setup_modes(self): 46 | # calculates 47 | for modei in self.modes: 48 | modei.setup_src(self) 49 | 50 | def add_mode(self, neff, direction_normal, center, width, 51 | scale=1, order=1): 52 | # adds a mode definition to the simulation 53 | new_mode = mode(neff, direction_normal, center, width, 54 | scale=scale, order=order) 55 | self.modes.append(new_mode) 56 | 57 | def compute_nl(self, e, matrix_format=DEFAULT_MATRIX_FORMAT): 58 | # evaluates the nonlinear functions for a field e 59 | self.eps_nl = np.zeros(self.eps_r.shape) 60 | self.dnl_de = np.zeros(self.eps_r.shape) 61 | self.dnl_deps = np.zeros(self.eps_r.shape) 62 | for nli in self.nonlinearity: 63 | self.eps_nl = self.eps_nl + nli.eps_nl(e, self.eps_r) 64 | self.dnl_de = self.dnl_de + nli.dnl_de(e, self.eps_r) 65 | self.dnl_deps = self.dnl_deps + nli.dnl_deps(e, self.eps_r) 66 | Nbig = self.Nx*self.Ny 67 | Anl = sp.spdiags(self.omega**2*EPSILON_0*self.L0*self.eps_nl.reshape((-1,)), 0, Nbig, Nbig, format=matrix_format) 68 | self.Anl = Anl 69 | 70 | def add_nl(self, chi, nl_region, nl_type='kerr', eps_scale=False, eps_max=None): 71 | # adds a nonlinearity to the simulation 72 | new_nl = Nonlinearity(chi/np.square(self.L0), nl_region, nl_type, eps_scale, eps_max) 73 | self.nonlinearity.append(new_nl) 74 | 75 | @property 76 | def eps_r(self): 77 | return self.__eps_r 78 | 79 | @eps_r.setter 80 | def eps_r(self, new_eps): 81 | self.__eps_r = new_eps 82 | (A, derivs) = construct_A(self.omega, self.xrange, self.yrange, 83 | self.eps_r, self.NPML, self.pol, self.L0, 84 | matrix_format=DEFAULT_MATRIX_FORMAT, 85 | timing=False) 86 | self.A = A 87 | self.derivs = derivs 88 | self.fields = {f: None for f in ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']} 89 | self.fields_nl = {f: None for f in ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']} 90 | 91 | def reset_eps(self, new_eps): 92 | # in here for compatibility for now.. 93 | 94 | self.eps_r = new_eps 95 | (A, derivs) = construct_A(self.omega, self.xrange, self.yrange, self.eps_r, self.NPML, self.pol, self.L0, 96 | matrix_format=DEFAULT_MATRIX_FORMAT, 97 | timing=False) 98 | self.A = A 99 | self.derivs = derivs 100 | self.fields = {f: None for f in ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']} 101 | self.fields_nl = {f: None for f in ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']} 102 | 103 | def compute_index_shift(self): 104 | """ Computes array of nonlinear refractive index shift""" 105 | 106 | _ = self.solve_fields() 107 | _ = self.solve_fields_nl() 108 | index_nl = np.sqrt(np.real(self.eps_r + self.eps_nl)) 109 | index_lin = np.sqrt(np.real(self.eps_r)) 110 | return np.abs(index_nl - index_lin) 111 | 112 | def solve_fields(self, include_nl=False, timing=False, averaging=True, solver=DEFAULT_SOLVER, 113 | matrix_format=DEFAULT_MATRIX_FORMAT): 114 | # performs direct solve for A given source 115 | 116 | EPSILON_0_ = EPSILON_0*self.L0 117 | MU_0_ = MU_0*self.L0 118 | 119 | if include_nl==False: 120 | eps_tot = self.eps_r 121 | X = solver_direct(self.A, self.src*1j*self.omega, timing=timing, 122 | solver=solver) 123 | else: 124 | eps_tot = self.eps_r + self.eps_nl 125 | X = solver_direct(self.A + self.Anl, self.src*1j*self.omega, timing=timing, 126 | solver=solver) 127 | 128 | 129 | (Nx, Ny) = self.src.shape 130 | M = Nx*Ny 131 | (Dyb, Dxb, Dxf, Dyf) = unpack_derivs(self.derivs) 132 | 133 | if self.pol == 'Hz': 134 | if averaging: 135 | eps_x = grid_average(EPSILON_0_*(eps_tot), 'x') 136 | vector_eps_x = eps_x.reshape((-1,)) 137 | eps_y = grid_average(EPSILON_0_*(eps_tot), 'y') 138 | vector_eps_y = eps_y.reshape((-1,)) 139 | else: 140 | vector_eps_x = EPSILON_0_*(eps_tot).reshape((-1,)) 141 | vector_eps_y = EPSILON_0_*(eps_tot).reshape((-1,)) 142 | 143 | T_eps_x_inv = sp.spdiags(1/vector_eps_x, 0, M, M, 144 | format=matrix_format) 145 | T_eps_y_inv = sp.spdiags(1/vector_eps_y, 0, M, M, 146 | format=matrix_format) 147 | 148 | ex = 1/1j/self.omega * T_eps_y_inv.dot(Dyb).dot(X) 149 | ey = -1/1j/self.omega * T_eps_x_inv.dot(Dxb).dot(X) 150 | 151 | Ex = ex.reshape((Nx, Ny)) 152 | Ey = ey.reshape((Nx, Ny)) 153 | Hz = X.reshape((Nx, Ny)) 154 | 155 | if include_nl==False: 156 | self.fields['Ex'] = Ex 157 | self.fields['Ey'] = Ey 158 | self.fields['Hz'] = Hz 159 | 160 | return (Ex, Ey, Hz) 161 | 162 | elif self.pol == 'Ez': 163 | hx = -1/1j/self.omega/MU_0_ * Dyb.dot(X) 164 | hy = 1/1j/self.omega/MU_0_ * Dxb.dot(X) 165 | 166 | Hx = hx.reshape((Nx, Ny)) 167 | Hy = hy.reshape((Nx, Ny)) 168 | Ez = X.reshape((Nx, Ny)) 169 | 170 | if include_nl==False: 171 | self.fields['Hx'] = Hx 172 | self.fields['Hy'] = Hy 173 | self.fields['Ez'] = Ez 174 | 175 | return (Hx, Hy, Ez) 176 | 177 | else: 178 | raise ValueError('Invalid polarization: {}'.format(str(self.pol))) 179 | 180 | def solve_fields_nl(self, 181 | timing=False, averaging=True, 182 | Estart=None, solver_nl='newton', conv_threshold=1e-10, 183 | max_num_iter=50, solver=DEFAULT_SOLVER, 184 | matrix_format=DEFAULT_MATRIX_FORMAT): 185 | # solves for the nonlinear fields of the simulation. 186 | 187 | if self.pol == 'Ez': 188 | if solver_nl == 'born': 189 | (Hx, Hy, Ez, conv_array) = born_solve(self, Estart, 190 | conv_threshold, 191 | max_num_iter, 192 | averaging=averaging) 193 | elif solver_nl == 'newton': 194 | (Hx, Hy, Ez, conv_array) = newton_solve(self, Estart, 195 | conv_threshold, 196 | max_num_iter, 197 | averaging=averaging) 198 | elif solver_nl == 'LM': 199 | (Hx, Hy, Ez, conv_array) = LM_solve(self, Estart, 200 | conv_threshold, 201 | max_num_iter, 202 | averaging=averaging) 203 | # incorrect solver_nl argument 204 | else: 205 | raise AssertionError("solver must be one of " 206 | "{'born', 'newton', 'LM'}") 207 | 208 | # return final nonlinear fields and an array of the convergences 209 | 210 | self.fields_nl['Hx'] = Hx 211 | self.fields_nl['Hy'] = Hy 212 | self.fields_nl['Ez'] = Ez 213 | 214 | return (Hx, Hy, Ez, conv_array) 215 | 216 | elif self.pol == 'Hz': 217 | # if born solver 218 | if solver_nl == 'born': 219 | 220 | (Ex, Ey, Hz, conv_array) = born_solve(self, Estart, 221 | conv_threshold, 222 | max_num_iter, 223 | averaging=averaging) 224 | 225 | # if newton solver 226 | elif solver_nl == 'newton': 227 | 228 | (Ex, Ey, Hz, conv_array) = newton_solve(self, 229 | Estart, conv_threshold, 230 | max_num_iter, 231 | averaging=averaging) 232 | 233 | # incorrect solver_nl argument 234 | else: 235 | raise AssertionError("solver must be one of " 236 | "{'born', 'newton'}") 237 | 238 | # return final nonlinear fields and an array of the convergences 239 | 240 | self.fields_nl['Ex'] = Ex 241 | self.fields_nl['Ey'] = Ey 242 | self.fields_nl['Hz'] = Hz 243 | 244 | return (Ex, Ey, Hz, conv_array) 245 | 246 | else: 247 | raise ValueError('Invalid polarization: {}'.format(str(self.pol))) 248 | 249 | def _check_inputs(self): 250 | # checks the inputs and makes sure they are kosher 251 | 252 | assert self.L0 > 0, "L0 must be a positive number, was supplied {},".format(str(self.L0)) 253 | assert len(self.NPML) == 2, "yrange must be a list of length 2, was supplied {}, which is of length {}".format(str(self.NPML), len(self.NPML)) 254 | assert self.NPML[0] >= 0 and self.NPML[1] >= 0, "both elements of NPML must be >= 0" 255 | 256 | assert self.pol in ['Ez', 'Hz'], "pol must be one of 'Ez' or 'Hz'" 257 | 258 | # to do, check for correct types as well. 259 | 260 | def flux_probe(self, direction_normal, center, width, nl=False): 261 | # computes the total flux across the plane (line in 2D) defined by direction_normal, center, width 262 | 263 | # first extract the slice of the permittivity 264 | if direction_normal == "x": 265 | inds_x = [center[0], center[0]+1] 266 | inds_y = [int(center[1]-width/2), int(center[1]+width/2)] 267 | elif direction_normal == "y": 268 | inds_x = [int(center[0]-width/2), int(center[0]+width/2)] 269 | inds_y = [center[1], center[1]+1] 270 | else: 271 | raise ValueError("The value of direction_normal is neither x nor y!") 272 | 273 | if self.pol == 'Ez': 274 | 275 | if nl: 276 | field_val_Ez = self.fields_nl['Ez'] 277 | field_val_Hy = self.fields_nl['Hy'] 278 | field_val_Hx = self.fields_nl['Hx'] 279 | else: 280 | field_val_Ez = self.fields['Ez'] 281 | field_val_Hy = self.fields['Hy'] 282 | field_val_Hx = self.fields['Hx'] 283 | 284 | Ez_x = grid_average(field_val_Ez[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'x')[:-1,:-1] 285 | Ez_y = grid_average(field_val_Ez[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'y')[:-1,:-1] 286 | # NOTE: Last part drops the extra rows/cols used for grid_average 287 | 288 | if direction_normal == "x": 289 | Sx = -1/2*np.real(Ez_x*np.conj(field_val_Hy[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]])) 290 | return self.dl*np.sum(Sx) 291 | elif direction_normal == "y": 292 | Sy = 1/2*np.real(Ez_y*np.conj(field_val_Hx[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]])) 293 | return self.dl*np.sum(Sy) 294 | 295 | elif self.pol == 'Hz': 296 | 297 | if nl: 298 | field_val_Hz = self.fields_nl['Hz'] 299 | field_val_Ey = self.fields_nl['Ey'] 300 | field_val_Ex = self.fields_nl['Ex'] 301 | else: 302 | field_val_Hz = self.fields['Hz'] 303 | field_val_Ey = self.fields['Ey'] 304 | field_val_Ex = self.fields['Ex'] 305 | 306 | Hz_x = grid_average(field_val_Hz[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'x')[:-1, :-1] 307 | Hz_y = grid_average(field_val_Hz[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'y')[:-1, :-1] 308 | # NOTE: Last part drops the extra rows/cols used for grid_average 309 | 310 | if direction_normal == "x": 311 | Sx = 1/2*np.real(field_val_Ey[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]]*np.conj(Hz_x)) 312 | return self.dl*np.sum(Sx) 313 | elif direction_normal == "y": 314 | Sy = -1/2*np.real(field_val_Ex[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]]*np.conj(Hz_y)) 315 | return self.dl*np.sum(Sy) 316 | 317 | def plt_abs(self, nl=False, cbar=True, outline=True, ax=None, vmax=None, tiled_y=1): 318 | # plot np.absolute value of primary field (e.g. Ez/Hz) 319 | 320 | if self.fields[self.pol] is None: 321 | raise ValueError("need to solve the simulation first") 322 | 323 | eps_r = self.eps_r 324 | eps_r = np.hstack(tiled_y*[eps_r]) 325 | 326 | if nl: 327 | field_val = np.abs(self.fields_nl[self.pol]) 328 | else: 329 | field_val = np.abs(self.fields[self.pol]) 330 | 331 | field_val = np.hstack(tiled_y*[field_val]) 332 | 333 | outline_val = np.abs(eps_r) 334 | vmin = 0.0 335 | 336 | if vmax is None: 337 | vmax = field_val.max() 338 | 339 | cmap = "magma" 340 | 341 | return plt_base(field_val, outline_val, cmap, vmin, vmax, self.pol, 342 | cbar=cbar, outline=outline, ax=ax) 343 | 344 | def init_design_region(self, design_region, eps_m, style=''): 345 | """ Initializes the design_region permittivity depending on style""" 346 | 347 | if style == 'full': 348 | # eps_m filled in design region 349 | eps_full = eps_m * np.ones(self.eps_r.shape) 350 | eps_full[design_region == 0] = self.eps_r[design_region == 0] 351 | self.eps_r = eps_full 352 | 353 | elif style == 'halfway': 354 | # halfway between 1 and eps_m in design region 355 | eps_halfway = self.eps_r 356 | eps_halfway[design_region == 1] = eps_m/2 + 1/2 357 | self.eps_r = eps_halfway 358 | 359 | elif style == 'empty': 360 | # nothing in design region 361 | eps_empty = np.ones(self.eps_r.shape) 362 | eps_empty[design_region == 0] = self.eps_r[design_region == 0] 363 | self.eps_r = eps_empty 364 | 365 | elif style == 'random': 366 | # random pixels in design region 367 | eps_random = (eps_m-1)*np.random.random(self.eps_r.shape)+1 368 | eps_random[design_region == 0] = self.eps_r[design_region == 0] 369 | self.eps_r = eps_random 370 | 371 | def plt_re(self, nl=False, cbar=True, outline=True, ax=None, tiled_y=1): 372 | """ Plots the real part of primary field (e.g. Ez/Hz)""" 373 | 374 | eps_r = self.eps_r 375 | eps_r = np.hstack(tiled_y*[eps_r]) 376 | 377 | if self.fields[self.pol] is None: 378 | raise ValueError("need to solve the simulation first") 379 | 380 | if nl: 381 | field_val = np.abs(self.fields_nl[self.pol]) 382 | else: 383 | field_val = np.abs(self.fields[self.pol]) 384 | 385 | field_val = np.hstack(tiled_y*[field_val]) 386 | 387 | outline_val = np.abs(eps_r) 388 | vmin = -np.abs(field_val).max() 389 | vmax = +np.abs(field_val).max() 390 | cmap = "RdBu" 391 | 392 | return plt_base(field_val, outline_val, cmap, vmin, vmax, self.pol, 393 | cbar=cbar, outline=outline, ax=ax) 394 | 395 | def plt_diff(self, cbar=True, outline=True, ax=None, vmax=None, tiled_y=1, 396 | normalize=True): 397 | """ Plots the difference between |E| and |E_nl|""" 398 | 399 | # get the outline value 400 | eps_r = self.eps_r 401 | eps_r = np.hstack(tiled_y*[eps_r]) 402 | outline_val = np.abs(eps_r) 403 | 404 | # get the fields and tile them 405 | field_lin = np.abs(self.fields['Ez']) 406 | field_lin = np.hstack(tiled_y*[field_lin]) 407 | field_nl = np.abs(self.fields_nl['Ez']) 408 | field_nl = np.hstack(tiled_y*[field_nl]) 409 | 410 | # take the difference, normalize by the max E_lin field if desired 411 | field_diff = field_lin - field_nl 412 | if normalize: 413 | field_diff = field_diff/np.abs(field_lin).max() 414 | 415 | # set limits 416 | if vmax is None: 417 | vmax = np.abs(field_diff).max() 418 | vmin = -vmax 419 | 420 | return plt_base(field_diff, outline_val, 'RdYlBu', vmin, vmax, 421 | self.pol, cbar=cbar, outline=outline, ax=ax) 422 | 423 | def plt_eps(self, cbar=True, outline=True, ax=None, tiled_y=1): 424 | # plot the permittivity distribution 425 | 426 | eps_r = self.eps_r 427 | eps_r = np.hstack(tiled_y*[eps_r]) 428 | 429 | eps_val = np.abs(eps_r) 430 | outline_val = np.abs(eps_r) 431 | vmin = np.abs(eps_r).min() 432 | vmax = np.abs(eps_r).max() 433 | cmap = "Greys" 434 | 435 | return plt_base_eps(eps_val, outline_val, cmap, vmin, vmax, cbar=cbar, 436 | outline=outline, ax=ax) 437 | -------------------------------------------------------------------------------- /fdfdpy/source/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fancompute/fdfdpy/49d3682a9cface0e2ce32932f4dbfc36adff9fef/fdfdpy/source/__init__.py -------------------------------------------------------------------------------- /fdfdpy/source/mode.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | from copy import deepcopy 4 | 5 | from fdfdpy.constants import * 6 | from fdfdpy.linalg import * 7 | 8 | 9 | class mode: 10 | 11 | def __init__(self, neff, direction_normal, center, width, scale, order=1): 12 | self.neff = neff 13 | self.direction_normal = direction_normal 14 | self.center = center 15 | self.width = width 16 | self.order = order 17 | self.scale = scale 18 | 19 | def setup_src(self, simulation, matrix_format=DEFAULT_MATRIX_FORMAT): 20 | # compute the input power here using an only waveguide simulation 21 | self.compute_normalization(simulation, matrix_format=matrix_format) 22 | 23 | # insert the mode into the waveguide 24 | self.insert_mode(simulation, simulation.src, matrix_format=matrix_format) 25 | 26 | def compute_normalization(self, simulation, matrix_format=DEFAULT_MATRIX_FORMAT): 27 | # creates a single waveguide simulation, solves the source, computes the power 28 | 29 | # get some information from the permittivity 30 | original_eps = simulation.eps_r 31 | (Nx, Ny) = original_eps.shape 32 | eps_max = np.max(np.abs(original_eps)) 33 | norm_eps = np.ones((Nx, Ny)) 34 | 35 | # make a new simulation and get a new probe center 36 | simulation_norm = deepcopy(simulation) 37 | new_center = list(self.center) 38 | 39 | # compute where the source and waveguide should be 40 | if self.direction_normal == "x": 41 | inds_y = original_eps[self.center[0], :] > 1 42 | norm_eps[:, inds_y] = eps_max 43 | new_center[0] = Nx - new_center[0] 44 | elif self.direction_normal == "y": 45 | inds_x = original_eps[:, self.center[1]] > 1 46 | norm_eps[inds_x, :] = eps_max 47 | new_center[1] = Ny - new_center[1] 48 | else: 49 | raise ValueError("The value of direction_normal is not x or y!") 50 | 51 | # reset the permittivity to be a straight waveguide, solve fields, compute power 52 | simulation_norm.eps_r = norm_eps 53 | self.insert_mode(simulation_norm, simulation_norm.src, matrix_format=matrix_format) 54 | simulation_norm.solve_fields() 55 | W_in = simulation_norm.flux_probe(self.direction_normal, new_center, self.width) 56 | 57 | # save this value in the original simulation 58 | simulation.W_in = W_in 59 | simulation.E2_in = np.sum(np.square(np.abs( 60 | simulation_norm.fields['Ez']))*np.abs(simulation_norm.src)) 61 | 62 | def insert_mode(self, simulation, destination, matrix_format=DEFAULT_MATRIX_FORMAT): 63 | EPSILON_0_ = EPSILON_0*simulation.L0 64 | MU_0_ = MU_0*simulation.L0 65 | 66 | # first extract the slice of the permittivity 67 | if self.direction_normal == "x": 68 | inds_x = [self.center[0], self.center[0]+1] 69 | inds_y = [int(self.center[1]-self.width/2), int(self.center[1]+self.width/2)] 70 | elif self.direction_normal == "y": 71 | inds_x = [int(self.center[0]-self.width/2), int(self.center[0]+self.width/2)] 72 | inds_y = [self.center[1], self.center[1]+1] 73 | else: 74 | raise ValueError("The value of direction_normal is not x or y!") 75 | 76 | eps_r = simulation.eps_r[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]] 77 | N = eps_r.size 78 | 79 | Dxb = createDws('x', 'b', [simulation.dl], [N], matrix_format=matrix_format) 80 | Dxf = createDws('x', 'f', [simulation.dl], [N], matrix_format=matrix_format) 81 | 82 | vector_eps = EPSILON_0_*eps_r.reshape((-1,)) 83 | vector_eps_x = EPSILON_0_*grid_average(eps_r, 'x').reshape((-1,)) 84 | T_eps = sp.spdiags(vector_eps, 0, N, N, format=matrix_format) 85 | T_epsxinv = sp.spdiags(vector_eps_x**(-1), 0, N, N, format=matrix_format) 86 | 87 | if simulation.pol == 'Ez': 88 | A = np.square(simulation.omega)*MU_0_*T_eps + Dxf.dot(Dxb) 89 | 90 | elif simulation.pol == 'Hz': 91 | A = np.square(simulation.omega)*MU_0_*T_eps + T_eps.dot(Dxf).dot(T_epsxinv).dot(Dxb) 92 | 93 | est_beta = simulation.omega*np.sqrt(MU_0_*EPSILON_0_)*self.neff 94 | (vals, vecs) = solver_eigs(A, self.order, guess_value=np.square(est_beta)) 95 | 96 | if self.order == 1: 97 | src = vecs 98 | else: 99 | src = vecs[:, self.order-1] 100 | 101 | src *= self.scale 102 | 103 | if self.direction_normal == 'x': 104 | src = src.reshape((1, -1)) 105 | destination[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]] = np.abs(src)*np.sign(np.real(src)) 106 | else: 107 | src = src.reshape((-1, 1)) 108 | destination[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]] = np.abs(src)*np.sign(np.real(src)) 109 | -------------------------------------------------------------------------------- /img/dipole_dielectric_field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fancompute/fdfdpy/49d3682a9cface0e2ce32932f4dbfc36adff9fef/img/dipole_dielectric_field.png -------------------------------------------------------------------------------- /notebooks/Examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# fdfdpy example problems notebook" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 2, 13 | "metadata": { 14 | "collapsed": true 15 | }, 16 | "outputs": [], 17 | "source": [ 18 | "import numpy as np\n", 19 | "from fdfdpy import Simulation\n", 20 | "\n", 21 | "%load_ext autoreload\n", 22 | "%autoreload 2\n", 23 | "%matplotlib inline" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "## Electric point dipole" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "This example demonstrates solving for the fields of a radiating electric point dipole (out of plane electric current)." 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 5, 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "data": { 47 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAW8AAAEoCAYAAACXYXDAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJztnV/Iddl917+/87zvNKZJjToGIZmUYAdEBbGNyZXWPwkdEJsLKxmC0GKLKAkUSqkpSsB401Yo9GLQDjGgQhmpILzgyHihBb2wzqQKOoHYIbTJ5CZm2iSNYTLvc/bPi7XX3mvvvfbe6/9ea5/fZ3iZ55yz99rrnOc53/M93/VbaxEzQxAEQWiLy9EdEARBEPwR8RYEQWgQEW9BEIQGEfEWBEFoEBFvQRCEBhHxFgRBaBARb0EQhAYR8RYEQWgQEW9BEIQGeeBzMBHJdExBEIJhZkrV1o/8yAf5jTe+mao5AMDnP/9/XmLmZ5I2mgkv8VbczW6bv4uLcW+y31E0DPnMEc5HTe8xzfS91g33Kq5Jr/XGG9/Eb/73X03a5oO7v/Jk0gYzEiDegiAIFcAAum73sLMSKd4E7bYJBJB23v19VEekbvoT5tv9ZQvtU8t7ao5+X6n3Wv8eY+qdeK73HIt4xzB8daMHwx8W0QOQORZa6g/ORZjr+6YpCHko+b7r31eMDsz3w8/E93lDSxHvEHrXTaPLJnrQ//wAF3pgHFnoj0iEWRCKwzQKaNcLt+IejAuQa9lpRr62G0Ayb0EQGkVik0iMqKR323f0RO/EdR4+r1DZp9ZsTxDOSMxYEONqZN6XSU2Juj9tlckEEe8wzFIlwmWISoguuNBDIwOfCnFNwlws0ilITa9vSc42GM3ZBvrimL/OzJehrx0e49LLSjcIutKJ5AGHVJsIgiC0iMQmUZguj2AOXl5wuaQftCztKon8I5+cnPGbQjIcBqxrc7PM65FCrt917DcU8z3I6EB0QdepgUrCZWKxiS75xhTFeSdiIuJ3C1FPKbolBLW0SN5q1FEa199rqQhmLoQ50R8UKf7WzIxbCzgAEN+NrzFdMmQlk16AThaV+ZA1NiGPyTq5BLmECJcW3ou47yA6D3FM9Tv1+RAI+Vv1EXyf99jWNwLV1qU/rhsEXCiLZN6CILSLxCbp2XIuLbnsUq5a3HR+fF5jH5e+xd7fT3T+vPKcYp3w2nt07shVpn2QgDKATibpFCGHaOeKRXKKdg1CXdtArAt7X+VTYvsdpRJ0k0nmnVAEzfdFykiD6M76ezhmzEaqTZqkJZd9lFi3KNBbbD2fEsKeW9DNHDklqTPpNQEvjlSbCIIgNIpUm7RDKzFJSbd9Nocdgu01KOnGa3fguWKUY5HYpAkkJhkRsXZj/jrlFPNWRBxIH6MchgxYliFGcFoQ7pyCLWKdhhJi3oqIn0PAxXkLgiC0iYh3WpJOhU/saFP2LZfbbsVpO081r9Th5XTi5t9GyprxHDl4yO9Hv3aHVp0wQCLe9ZFStHNk26mF+2jBzrmMQGjbpUXf/B2kFvIck35SCXm7EQrLTjqCIAhNIs67Lmp13TlikpKOu7XlZHNN/Xa6dmIXXnuM0qT7lkk6dVGbcLco2K2JtC+lRT11vptSyFNWosRk4PP+lIGlVLAGahNtIK1w5xTss4u1K/PXIbWY58jEU+XhN+nCb9x5y7teEIR26bq0/3YgomeI6ItE9BoRfWrjuL9JRExEH0j6fA3ybsbg6IDP6rpbWvr2jOR04ildeKqJPandN1BvmecRkPqlPwfgIwBeB/AyET1i5i/MjnsngJ8G8Js5+3OoChAuVQn3xfgvrh93SYVbv06pXy/vfvR7k8b8O5Jcr6P+fcf+ztP87SXecrBqo9CXCqb8t80HAbzGzF9i5rcAvADgo5bj/gmAXwTwZtrnO6XIbyb7AF2CP9hUTjvVcy0t1qWEtyahzyXksaQS8VTsvT6HfSjrzLtcbPIeAF8xbr/e3zdARD8I4Clm/vdJn6uFagYsBUEQvElfbfIkEb1i3H6emZ93OZHUp9gvA/iJ1J2ycZh4x7qds2bbWWc6NrZD/Vp/c2y7lXLJ1FR5eGwlSq5VCafXOHJjhiwLU32dmdcGGb8K4Cnj9nv7+zTvBPBnAfwGEQHAnwDwiIh+lJnND4QkHCLeZxHulBFJSloTaV9yi3rKwbpYcUtRSphiILPKAczypYIvA3iaiN4PJdrPAvj40B3mbwJ4Ut8mot8A8LM5hBu44dgkRrhTiHZNA7VnYf46pNzcN27iSpwTT1GNkqoSpboa8IKTdJj5nog+CeAlAHcAPsfMrxLRZwC8wsyPinUGNyzegiC0DhffBo2ZXwTw4uy+T68c+5dz9qXs7vFJ8uXwNmqISY5+DW6JlE48pQsPjVFip9WXyMAn5L6O7KTTBkeKtrr+8TsBlSmfO3ZpWka+wa9Uy6nGCnmKtVJisvDYCKWq6OSGp8c3I96CIAgTxHnXz1GuOzYmqTkiOdphr7HVr5SuPKULD3WhsQ78SPddB7KHZdW0KNy1lEIC9Yp0CLbnkkLQY7PgI2OUmEqU4hl4DsR5J4A7gNYf9hW0WxPtZNPPTyTWLsyfb4yYp3DjsU5cXLgHjOLVJjVRvfMWBEGwI5sxVEdrrvtIx32E075E9LnL7JRSOfEYFx4To7TivquZcSniHQaDt5KSIFoS7lDRrlWwY0Q55TVSCrz5WsUKeUi0EBKjnC0DZ9yuwOakSuftS0tuO0S4U4p1CYGOZauPMcIe68pDxS00Bz/KhTfDjW+DdgrxFgThRpHY5HhCo4SSrrtFt92C0/Zh/nxSOXEfFx6Sh4fm4EcsuZqy+iRrFQvLgGUUwy9nFn77CN0Ra3WUEO7Q5xUj3GcT6z1SiTnhLigTDxE638G+0Ay8xvw7ORKbCIIgNMj+vpOn5VDxPqKypFbHHeq2czntI0oQU8yWjHHiJWMUdT2/gczQCOW0E3hkbZP2qFW4S4l2KsGubTbmWn9iRN18rUoJeW4BB8IilPNVn0jmfQglByhL1HD7Pp/Sol2bUPuQStRjhDy3gAP5BzJDM3CX55Nz79VNJPMWBEFoDIlNyhPiumuMSkrEJCFu+wiXPX/dSkybjpk96evCfa8VWk5YawZebfWJiHdejvpKVZNw+whqaDySQrST7foT2E7winwRsyf16+0apeSMUUpl4KdA6rzzkWLPR8DfdefOuF2Fu0SuHSPYh+WUG9j6FDS1vH9dcol4qBN3EfESGXjoAOb8g0h92Bz3wcEi3oIgCA0idd4h+L9oJbLuWqKSnDFJqNuu0Wm7EJOnh+TiOWOU3BGKr/sGwmZgVoEMWNZJih3f92hNuH1FO6VYXxIPgnYxO94ERiu+Qh4So+SIUHIP/vpGKIvohO6OG8gU8T4HPq7bVdhyiHatgp1aoEOvFSLs3uuFeAi5r4induE+z+2mBjBvfMCyze/RgiAIN06Vzjtnzn10VOLiun3cdqjTLumyfVnrm4sjD8nHXSMPVwdeQwZeqvrkcG7YeVcp3j6kKkdctptWuF2jEpe2QgQ7tVj7Dj6nyETnz8FXzPeEz0fEXQTcpS0g3wSYW4hQpFRQEAShNaTapAyuTi1nlYmLY609KvFx3SFuO9fGGK7t+rhP8/m5unDXGKXWCCXnru1Nlg6KeB9PDTl3SuE+IibxFesjdjDaw9YnF0F3jVRcYxTXahQXEc9VgXLz+feNV5tUI94+5BqgdG8zXrj32sgh2CnF2vd1jXGK8377iPmWI/cR8lgnHjJdf4+cAr7fXiULVckMS0EQhLZgAEd/dhxJFeJdYjblHi6utFRUktJ1+69+mGtbNcfM22kiivtyqy4OHNh3sa7Rx14liks7NbjaJvJvGbBsi9SRSaoVAksJd2rBrm29E986bVch94lR1q6ZqpTQtZ3UA5inLB0U8T4GH8d91ABlihruEoINuD6f46fP+0x/9xFzFyF3qVBxFXF1jL2NVAOZRw9g1j54KbGJIAhCa0hscgw15Nx7xEYlKcoA99zuntv2ddolps3HLErl6sRdcuO9KMUlkthzzyky8KOp2n1X2q0SNOG8j4hMYrcUyxmVpBLsGtc3sfUpptzPNUrZu0aKwcyt84H1CMZ1APPI0sFDYJbp8Wch9QzKLbZcd4xwxzhtl+fvVRde6NvRnuC4zqR0EfLQLNxFwNV1l+e6rIXiwpEzMKutPqmsOyU5lXgLgnBj3K7xPka8c1WZpCDlCoH29u3n5opJnCtVDhyDWLu2zT36TINPHaPEuNrU0+hTcMrSwRviFM67VM4dM0AZKrAhMYlTLfjBA5mp1ubeijtc83CbiG/l4FsRSu4BzBz5d7OwLAkrCILQJif/fNqiWvFOGZekGKQs7bpDByY3XXziAc0YQnbL2Ystgt3yykDgVinhVl9c3Dfgvju9DZ8dePbbanfSjkzSKUSO2u5UWW1MaeDauamjkqC8PNHsTZe2XNn6Ou+SaW/FIaExyl4line2HrGKYKoVCHOu/V0FDHHeufFeHKmg647JuUtl3L5t1T6AmXKAck/IfUS3dAaeIv8+wn3XgqwqKAiC0CLivNukRGlbaElgyozb1lZITLI7+ccpD0/zmq9lpimqS0JiFNcIJTQD3yLVBJ4tzlx5csN7MdQn3jVFJinPTRWV+MQkcVl4vg/Htbbnor4n5jZhDolR1iKU0On0y/bD67dTlQ46Xcux7tsctEwZ3YQgsUljHO26fQcoSwv3qrvf/EaQbmDTBZv4zfuwJuZrjtzHibscu5eBu7aj7t+ePg/EVZ/scUr3feOxSf1L+wmCIKzAXdp/exDRM0T0RSJ6jYg+ZXn87xHR/yKi/0lE/5WI/nSO5w1U5LxL13Wvuecc1SXW4xNk3PNj/StP4qtSQnFZPXBtMaS1aGQrRnGJUHwz8DVSV5+4lA7eauVJycyblEg9B+AjAF4H8DIRPWLmLxiH/Roz//P++B8F8MsAnsnRn2rE25XYyCR2qVcffAYnXaOS2JhkTbBjJ/eEsia+wCjAZp9do5S5ONuO841QfEoIc9RYxy89e7K6bwbQUckrfhDAa8z8JQAgohcAfBTAIN7M/C3j+O9FxqWzsor3EYsdxcymTOm6Y4U7NN9e/xAIv4a1PfZ7nTvyrzCxieuakK+Js4u7ds3L1zLwkAFM1Ye0y8cePXhYmgPqvN8D4CvG7dcBfGh+EBF9AsDPAHgCwF/N1RnJvAVBaBQCc9p/AJ4koleMf3/Xt1fM/Bwz/0kA/wDAP0r9rDXFYpOtfNUl707h4lNHJl5VIREZd2ik4uq2V/vh6a632GrLdOW2PHutVtvmwufO2jUaic3AfatPQkkxdd6lT00sF8tZnPfXmfkDK499FcBTxu339vet8QKAf5aqY3Oay7y3yBGZ5MrIU2bcoaK9OG9DYFPXfZuRx/y6WsxtkcqWkM9jFF9xLiXAY7v2DDumdDBl3XcLFH6aLwN4mojeDyXazwL4uHkAET3NzL/d3/zrAH4bmTiVeAuCIOSCme+J6JMAXgJwB+BzzPwqEX0GwCvM/AjAJ4nowwAeA/h9AD+eqz8i3oHEDlLunZsqKtk9fsVtb8ZcEd9G2FJBotHO2ezTPFLZctMh7tvnuMk5HoOXp5wgY3DULkwM6Jy63DWZXwTw4uy+Txs//3SpvmQTb6daa8fa7r0/jphp8ClnUrr2y6U+28aaEO8JtvWavC366pydFRcdX4epoC7bXBP0Dt1CyOeZ+DxGmefgrtHIHFupoe+mxpPj1vLzwFUHY1ccdP1AWav5rmJDYga4bKlgVYjzTkTKpVb3xN18PMZpuwp2bN69db4S2PGabBmQNB15qBPfO9ZpEG9FgOf4lg4K4cjCVIIgCA1SOjapidOLd8rIJEVp4N65uVz3Xkwyf77LttO+Sbp+4tky5li6cNOBr8Uoa7GIea7NfZvHhkYssaWDoZN2Su82XyMSmxxAqby7FnxE2fa4ecyWaPvEJKZQuog1Jar7ZupWPgzmmXd/vEWIgWmMYhNeW4TiMsMyRcRSA3tlg64xUK1rnTBLbCIY+FRSuFaX+I7Gu1aezI91Ee4thz0X1DWxjsnAO3SLdpm04FJ/zOjKbW7c5sRtIu6zdZn/FPep8KWYOi9O2heS2EQQBKFFOolNzklo3m1vK+FUcQ9nvVXHrdtxjUpsMcmW215fgTDxbEvjq+8yUllm4maMsleJYmbPtjpwwB4bxDrzLXxX99uacZlqp/kmkdikTlrMul3ikpCse3zssn/MjnCvxSRatO1T61MOXlpquU2Btgj5Woxii1DWVi/U4rtVnxwygDkX+RpX9ktV8713jdIcMUmnJg4R75QbL6QktsIkBp+qktXjLAK8Nih5AVldtl28aXGtUO4wd5wbNeC9kF96Qe7AE/dsc+FmBr4lSj414LF47Z1Zae5d60JVIt6CIAgN0ol4n4uUWbfzNXcik5ice62doXTQMePei0lWI5WVfNx27BwdeUzvM6/TTY6d5Ng6JtF9HSIRs3Z7GqHMM/DQ6pOtx/ZKB3NFJ1LzPYNJ6ryFNCWCobjk3OZxa5NvbOWA84HJeVSyJ9jm/XORdsm+zczahl3Il7m47vt0QHMZoaxl4GsDmGb7036nj070dfe46UFID1TmfXQvjkPEWxCEZpHYpDJqqTSJXT0wpN2QQUHfqGR8bDaAObttnjt15X5vmDvjeAZjWkEy/qxduHbgOkbR6AhlOqlnGqHYyghd8Skd3G3LcVOEUrM1S1ScCGWpUrxzkSvvnuNX/md/zBaXzNuer1diKwccHptl3Athn92eizdZhNy1ZNCMTezByPz4qYgvar3758Jk5tDLMkIAq9UnZiyyJvRbUcdeWWEuYnbZOSNSbXIicm1bBqTJutectc9SsVvrleyVAy4ycOP2mmDbxJpoO/82BfsOBOa50x6nwl+MNqZCr3PqMeNW948Z+FoZoX6+WwOYa6yu3Z1AoHMuF1ti0LKmdU4YEpsIgiC0B4vzvmlidsvZy7pDnfpaZLJ23HKxqfXKkrWoRLvutXjEdNqXldT70h/TMU9ybgBgGp226cTVfWbfp3Qwow6aHDEvIzRdu636ZNHfjanzruw5aZeywZBddgTFLYdHNy/eKfEZbAwW9p0d3pflfPaZk1q4JwI9v03TuGQIL8ieeWt934pQiNXXXX0wgXFhHo7rYBdwwJymPhXw8blOBzDnbE2f38JvZUAZ+CuHrCpYFbVUmqTGtcLEtn7J1uJUhLulMK+sU2JWlMwzbprfJpqI9sW8bRHpSQRO0/rb6TJTKtfuzAxct9efszao2Q3+eGx8cNZsG8CcrgW+tjmxbd0Tn0k7rZBqfe9akMxbEAShUcR5F+KoBalSlAimnlUZ1IednWxspXtmdclWxj3cNiKROzIjFCM+oem1Lrb3T39fx6raRLtlXWcy2XhBO24a3bd6bN1962c3j0fmGzosXo/Z5g1H4DPbcrWNjanyt0QnMyzPQc4ywcW1PNcycX1scZ3NuMWyCiKb5YBb+bg949YDjfOY5M64fSEdqxjXnQm4jk3uqBdhIxIhAFc9SYdpEHpi4Loh4DZBni8ny7Qc9APsU819YoKt3DvVWidJlma9oan1LNUmt4vPErD5+mBbIMptrRN9e2uyjFnPPa/jnjzei/PF4ryJgAdkunLg7jKbuDPrwmRdbjCuneHaJ49hcN46Kzcz8Gm+rV31OIln1WH3/n6t7nt5/HLSTg0ZsFScbNNt/O2fnZsWb0EQ2kYWphKyEuvm16bBL65jRCbWdizVJfOMWz9+RzREIQ+IJrfviHBHo9u+DGV/CvP91DGjY4JOma7MYMMt3cOoCdeB+CQDp0X1ybrbvgyO3xafmA42tGxwbO94V37rMEiqTYT6cBH8vT0m56WB02PmpYLjwCQwRiVAL9YXDDHKnc7ABzEfzwGmbujKhI4x1HJfmHA1sxEoAR/6wNNFq0yhvxr3A/uDl+ZrsTUBp9XSP0FiE0EQhCaR2ERYpeTGC3uPb+0v6Xbt6fT3yZT3PhbR7lpHJQAG1/3wYjpv4M64vSzpU1wZuHasqkrQD1ZOyk+m/b/2S8aqc1n1kbUzV98jtjZ3mD/f+bE+GxD7Pu5LzkWqbgGZpCMkx0XwXTcYdoFW6r/ndd0miynvlhmWZsb98EJ4cNG3gYcXwkPj9t3sPXTl8f+PifC4D6OJ+6v22tkRj7Xmfcm3lttuEZNMb6v79HOfiqC57ncIWxsU249PK+yCGyyxSf2ETosvtYZ3KTb35xz+s/9Bm3Xd6vixNJCoL+Mbpr7PM+5RoL/nQnjiDoN4P6DxZ83jXuvuWTtzdfJ3OwbTaLg7GhepYhrrwHX/mKdZt2rWVu9NMP2/zVmfrewudKJOrj02hbI0I96CIAgTWGZYCp7sza5Myd6U+FCIlsu6mqWDKudW9+vSQJ15P3EHPHEB3tZ/CXjbHeMhTatNHvdvqjev0+t0UE6700vEEkM/xa4jXAynDSgXTrYylgTknCo/LyV03RZNcEcy70ooPbOxZUIy8r3se/y/gkBGHbcanNTRyMNeuL/3gRLTt98x3n7X4WE/CPm4I3znqg5WHwA0yPGVVfngVZcOEkB6MLMPNXRf1NjmdIZlZwxoug5cqnPD1uu+RdopnSTJvIXz4lWNQvPb9sz7ASm3/fY7JZ5/9Il7vOvhY7zj4T0A4NuPH+Abjx+qg996oAYtO3tbVzJm5fR9uDpqsq2aRLgtJDYRBEFoEHHeAoDbim7WdsEhIyqZHj+65YcX4CEBb79TX63f9fAxvv9d38K73/cHAICvffmdwDe+DwDw5vWCN693Q+TyVresCb+Y12ZjhUKe9vV6Ay67ncjieFTmfXQv4iGiK4B/CuDnuS+9IqLfYuYf3DpPxPuGuRi13Db0Q7ZjiDBk3O94eI93v+8P8LbnfgoA8O5PfBZv/L+3AwAevvXE6vnmNazX70sMr7c8jU7Y5CQDlq9CeZr/SEQfY+bfw/ZbA8DSBAmCIDQDJ/53EPfM/HMAPgvgvxDRD7l0R5z3DdPxWLlh+5zXfz0248vGIOS3Hz/A1778Trz7E58FoGKTbz9Wf1qPO1o937yGDWYMe10Kwhz193EK500AwMz/hoheBfBrAN63d5KItwEbC/Cfnc5cihW9mI7LiCyyxA5jFcjjTtVx63LAbzx+CHzj+4aoxKw2+c71gsc8zri8MhaJ7rCM6+z/Zl9vBcm7/TjJq/VT+gdm/t9E9BcBfHTvJBHvk2NbD2T1WJ6uUaJdr6rLHsX7ntXkm+HYtx7gzesFD996AsC0zvs7V8KbV8K9sdaJ2dbcWfsMQN2SqAt2Wt4GjYh+jpl/iZk/T0R/i5l/HQCY+ZtE9Kf2zr8NmykIwunQC1Sm/FeYZ42ff3722DN7J1fjvIdpxPJ5soueKegz01LHJNqt3s1mKRL0Lu8KBg95Ytcv6/rYmLRjrkl4ZeDN693q9Pg3r2Ns8rhTbXVGPMN9H/S1u+H2zJWv3O/2/E/yBbsALUU3jZcK0srPttsLqhHvlmDuJuub5MzKO+qSrW/Cwz5jADODZzV8HXhYZvvajVuXXVitx62XdTWnrwMqJtlaVfBxB7x11fdzH5voSAa49scy80KYub8/BznWNNHMBVDWNMlB89PjeeVn2+0FpxfvjrtTLQvLuK4uCzu6y3F3dcyONTPwDtyvr623HBvdL9EosBdWC0bpY7/bqY8rnVvfkZp8YzJZz7vDIPzzzPvKo8x1rFz7OGg6FfMOPLj05XNndP1/a5xpOVgAQcvBnokTTNL5c0T0LShH9Yf6n9HfftveyacXb0EQzkvLzpuZo7bpaka89dfO0E0ZStLhurubjpnxd/1WuqHoHWNsO+rMV+Uz778zVvvr+rfBsBECj28MtWEwhkeZVJRx5TED39sGberEeXD1ymmPWbb+Byx31Jk/J+XE7e4zZhcd1fZ4vksG3NIOOhLhnINmxPso9Jsy1V6We8K+9bhN5M0lUvevzcbZ/Q42el3tfsKOdf2QjpSad+PNjsZp69u7x/cDnmbGzTzk3Fdm3A+P8WJijpl3M5aZ+N7zXd63Llx7ApxaoFsS/FppPDaJQsS7Ulyqb9Ycu5l9X/qfu9n2aGOVyTQD1xsFM4B7U/w6QteH3h2pn/WCUlcya0+mIy0dcy/e/bG9QGsxv+9vA/2MOSPVnjvxed9Vyq1duF2UXapMWqquEEaYRbwFQRCapOXMOxYR7wLElhLqkjZdMqirJuZVJ0wdOl6v/57m3yoFuei8We+JYNhnXQt+P7h0o8zwMu6AA/BiCVnTETHGmKTrz783Mu+rkXlfjQoTXTo41oFvxyYdutWse15pElsmKG69Dko7byJ6BsCvQJVxfZaZf2H2+M9ATXe/B/B/AfwdZv7dHH25afHeKrsr14duGLQEdNDhnnur83Rp4NKFjKWB6kzNfCuxCysB1+WAMDa4MQcxgX6X906tPK2ZL/tq5t5asAH1ZtMirY8bog8t1oaYz5+LOUi5LeS8iExc8259XA0CfbbyxpSYpa0lIKI7AM8B+AiA1wG8TESPmPkLxmH/A8AHmPk7RPT3AfwSgI/l6E/9pRuCIAgrMFPSfzt8EMBrzPwlZn4LwAuYLSDFzP+Zmb/T3/xvAN6b/En3nMp5p3DSrtP092ZZbrvn/VLCtXanjy2fr45ONFsRio5OhmMZuJoVI3pXHVZVKONAYn+sPm+6DeX0OnrCDaZOm437zdjEnGWpI5O9qET/3xaZbDlXH2e9VRkyfyx0dmUKp39LTj2T836SiF4xbj/PzM/3P78HwFeMx14H8KGNtn4SwH9I3L+BU4n3GnomWsxMSx/BzcXeVHlb2eC88qSbifllOK6/rUXVEGTdrpmoXI1rXXkvNuHJ/R14KAdkmMI+r/Oe3taRyVaFyV4pYc4p8a6kKBG89dmVmgyZ99eZ+QOxjRDR3wbwAQA/HN8lO0XFm7kfaKN1Edwb3Js73lbYcvTmc9aZtllfPj/XzMcZ14k8A+MElfngpRLhsXTQxObCO+28+63I5svLTt43bK/z1tcdfubpBPd5xm0boLSVBo7nd5PnbN7Plhx77G79jVIuAAAVe0lEQVRnPHZdHLPlgmvIwkPY+wbQ4vMqPF75VQBPGbff2983gYg+DOAfAvhhZv5urs7chPMWBOF8qLVNipYKvgzgaSJ6P5RoPwvg4+YBRPTnAfwqgGeY+Ws5OyPinRCfZW1DZ25uRSe68mQ6GWd0U6YL55UIxVyWdZywQyAjF2FW0cncBQ8VLJZVAOdT3eduezxuGpPYpsCbOff0/mWFyeTxwMjEJ+Zo0b22TEnnzcz3RPRJAC9BlQp+jplfJaLPAHiFmR9B7QL/DgC/3r9nvszMP5qjPzcv3qs10zvxDbC/3kqwQGMsBzSz9uWgaDdEJ+ZzGOIN6ob1TpYrDtKqgI/tGxj7XV7BEzHX7Zm7vC+Wdl15bL5SoC3jnj42XTlwiIjm17NEIer+ZVxiO86VPWF3GaxcXZ/lhgYfgzhghiUzvwjgxdl9nzZ+/nCpvpxOvHPWbqdY52TtQ8HLtRuTdmx136PwMy7GolVTgboMAq6OHc9Rj449uSrvPc28eTo4al0TZejTUrjngm37/7ye2ybc07bX67p9XPe6mMa76pzrmZQQez1uVQOl67xr43TiLQjC7ZBpn44muCnxLrUxQ4qa7/mMS/Xz3bQyZZZ/628dtm3SuI9Q5u57/GkZocB65NKJ+8Azd23+vOW4zf/b6rnHWZHr0+B9I5OY2u5cSImgCaGTtU3qopZyQdc1SXz7sz3xxn8dlHnp4Jh9T6fOsyUDn0QsE3G7TGKSZQ2531K0a7eng5XL/Hot49bHTcv74jLslOWBJSfmOF3nhGWCt06V4n0EPll56gk7rmuZ6OMmGzkY7ts2gDmdpEOTjRuWAjd14mMfthe62hJx+5raS8E2759k1Rbhth1nG6C0uW7XQcoj1+6WgUp3JDYRBEFoDBmwPCFr5X8AkkyVt17TYa0TYKxUcZ1xOcdWOrhWfbIWoQBjGeE0W59WqgzH9sdoPzjvm2/2bXPb4+2l63Zx3Itzabky4Jb79YlMUq1l4stW3n2rbl02YygM83VzivxRWBd6WhHZHNEJYBd32wCk2b/5AOY8A1ft3C3E+WLmx5tvgnkteLg4bYn1/LathntPuNcGKJf9WD+uVGTSUs5cU4mgyQ1r9zmdtyAI50dNjz+6F8dRrXjvTVqpcTf5eZ9sz2Hu2P3KCpeLVi2OsQxgqussywjNChJzMSvN6NLXBzZ9sa8EaK8mUY8tXfdeVGK/rn3Gpe2YoS8Ojjx1ZJIj/ihRaXLIjvQsA5anZauCxLfmO3Yrs8m1dwR867p71SfAcgYmsFZGqB7B8BNNS/EyvDFs4uki2MOxjsLtUl0Sk3PH4CuWknWv007wlJ5Ti3cIW4Odc9Yc8N7gpUu7c3FXfbLtFL+x9slGGaFqb+nENXMhB2BZJyWMtX0mV5d7nU+8cRBtdZz7AKWvOLs6bikRzIfEJoIgCI1yw9p9nHi7VpzUMtsyluWGCtulgzZXb9useH6s6QhtZYSauQtf+sZ5hcnSicdgn7yzHpHYHt+qLJk73q1NhX2z7laqRFJl3bVWmgDivE9NaO4dWzbo+qHiO4Bp23XH6VhDxG3nLpeVnQp9yDomLuwJ9vyYrZhEHbsu+L6i7Bp52ETSpzxwKy6RvHsdBsCytokQi2vdt9M64RYBB9ZrwPcEXB8L2AczVdtjVYrGJuQma5sbz9nLyNdEaMtpq/PyCbe9n25ONeeyr8IUcd6CIAgNIuKdAeYOe99oXDYkBtxyb9XOegQC+E+XX4tcfFYbtPXLp7Z70teVWGQZcVyN2yuZuiVGMZln4iZ7jnyLzYjAlkdHuG2X49f74ubMY1cPzBWZ5M67YyuOUsCQAUshAJuAu5YO2nBd+2Q/I1/GKLZ2ddumOJprg9vEfLxmfCwQstdkLuEOEXif0sBWBjhDOez5HbANWk2cSrxjKk/WBi996r59CBVnfQywVakyrUaxnWOep8+di+aWmKfEVaxVP9ycYMjsyNJrkKxm/RGzFQ+Z6XggfMPeu/4aO0EQBGFBMec9/zpv4lLz7bNB73obaTcn9i0dBPbzb9v5MRGKZl4Tru7bvsbWWiGmK3fBdQPgGLdtOz8mKvHJuUu59hSRlVNlTcW13RqZYZmRFILrfc0M0QngL/xrg5C2/rnm5z5CD8wXxFqPUszr2N7Y1mn5iSbsbC/bul3zvdeOqyC7HpdiCrxqO2yQcrfdG4tMABmwFARBaBJx3g0Ru7pfjgHItT75VJ/4RCOaran0a/2yRSlmG+Nj9mvmxCce0az1zaXUz2sWpKfrzvGaxUYmZ6x6kSVhK8C15tutre26b2A9Btmr+wbswu/7oeKbgQP74uxSUTJt1y7kZlvj42mrbVyiBp+IZK3NFMf6xhHbS836RyYuop0yMmkh7wb6zPvoThxINeLtQ8q1tdcIyb9DtkxzzcDX2vEVe82WkKtzt8U8B/vT6P3y8Vxu27cddX+enNuVM7puQGITQRCE9pCddOoi5ebEe5UnMaWDIdUngD1+iMnAzWPnx6+VBc7PsV9n6dRcF6Law3XCz55b9J3NmNt1rxGTVcdOg/e6lmNcMlnw68AKF4lNGqVEGaLvVmmarVhnq4QQ8MvAAbdBSvOc1fhmR8xVG3nfKi5f7X12xwk5HggrCQyNJSQyiUOcd2Z8a69Lu29gvfokxwBmSAauruOeg2u2hB9wF/O164fgIyZ7LjfEaa+dF+q2Uw9QupwL3OYg5Zzzfizt06zzFgThtmEw+Iatd1Hxts3yiyVV5UmO/HvPMQPuGfhWe67Z9lY/1s5faysXTiv6JXTbw2OJXXfOnNu9nfP7Uqk2qZDSdd977OXfW+KfMgPX7QHuMcr8vLVz9fk2jqjznhMygOlybuqMe098U+TcR0UmNazjbXLD2l2vePvgOngZW32ylX/r81U//F24Twa+1+aWE5+fq9l77Y7Y2ivHAObk8cIZN1Au574F1y0LUwmCILSIbMZQnq3lYeekrDxxup7D2iehJYSqff9SPtNthcQoJkdUl+yRsvpkr00X55pjvRKXqKT0bvCtVpgIilM5b5fByxT5NxC3fOxeBg5siGxAjGJrf+sa8/aOJlawh8cjJt7stl1g+rvLB0+u31ltWbfmlnfSOZV4C4JwO0jm3QA+0Ylr6WDOqfMu5++55BQxylb75jVMUleV+OI/9TzcbbteM8Z1u3DEIOVZIpMbLvM+Trx9cu+jyFl9Mh6z/WGzVYkC+Am56kt4VUkqYY+pXHEVqBKirY7JW11SA7VGJgDQSWxyDD6TdnzqvlOVDqq24gcwzTfoVhmhenx70NFFyLe/UfiJ+Vo/SuHnJuMF2+WaLoKbaoDyaNdds3AD4rwFQRCaQ1YVbIzU+bdr9YlLhOJSPhhTiQI4TsDZiVLm1zMpuVm0Dd9qCVdnWspxA+miktTVJWfJuU1kbZODqSH/ThGh7GXgZjsxAj5cbycPB/yEXF/bBV+RT1nC5jM1PIVoq2PKCXcNu8DXHpcAkEk6R3cghBzVJ6pdt6VrU7jwvQ+CkIoRHyEH4mrdS9aAh4hZKtFWx8Vn3DkGJo903TV8wKjY5HbVu0nxFgRBAGTAsgp8l4vNUX3ig2sZIbAdo7iWE2p86rZ9nTgQP/M0llBHl2oW5nhcmpjEpy3g+OoSoJHIBGp2pTjvArhGEjnz79TT512EF0gTo4zHucdAPpHK0L6jePiKfI6v2akn9IzHpSkFdG1rOPbA6e9AO6JtIs67YXItXOWzdZvLbMxUg5nqGDcnPrm+pyvf44jMM8ca4NNj63bbvpyxumSOOG9BEITGUGub3K54Vzk/3ffrG/PV2WWolCzdFOux3bSuTf/bP7ab/HOlw3XxrxZsffPJtH1fD9fXuuPuUNctOfcSTvzfHkT0DBF9kYheI6JPWR7/S0T0W0R0T0Q/luVJ95zKeedawApIn4FrXLNwl3bV8f6RytCvAuuauFwrBO/JPR7X91nStbXBydYp+ZFDSlyeA/ARAK8DeJmIHjHzF4zDvgzgJwD8bO7+nEq8BUEQMvJBAK8x85cAgIheAPBRAIN4M/Pv9I9l/1yJEG9K1wsLOXaan5NjAo9q1305WZ9deVyd/Xh8uqnvNcUqoRUXvhNljnbcqt383tI/puxmt4/52zhgks57AHzFuP06gA+V7IBJUecdsouNb+mgb/WJTw24b4TiI+Aa1/VRND5rjte2jokrMQIWMrPRd+ebWoT7VnLuEc6xtsmTRPSKcft5Zn4+9UVSkFW8x4k0kVuOBQi4uq6fsOWYRq/J4cRDrzGea5mkc6CgJ13/JLNo+7af222XEu6F6z74AyCD8/46M39g5bGvAnjKuP3e/r5DkMxbEIQmOSA2eRnA00T0fijRfhbAx0t2wKSIePu42qTXDYhQfNy3JmUlCuAfo8yvMfQroEIk1EnNX7fSjixm4aecMQlQV1RyNsoukMb3RPRJAC8BuAPwOWZ+lYg+A+AVZn5ERH8BwL8D8EcA/A0i+sfM/Gdy9OcQ5+0z+KcJHcDMmYGP1/AbzFTt58nDbdfyuV4oR3x9Potgj9coI9whkUkNqwguKb+2CTO/CODF2X2fNn5+GSpOyc5hsUmIgANha5/kzsDVNfyej6+IA+5T7LeuZ5Jb0FORajlVX8EOvb6v0JXIuIF0OXctyJKwgiAIjdJ+xUw4TYp36MqDOTNw1b5/KWSMAwfCXPj82jaOcOU5Niwo5baH8zK77pJRiQ/HVJ0wOP9cmGo5VLxDxE4Tk4Gra/pNdCkl4upaYUIOxIn5Wn9aIlSsgXKCPV6vfuGuNTIBJDaJFu81gco1ezEVuV24ukbYh5PPBJ85ucS8VmLE2qSkcItop0NiE0EQhObgwycJHUk14h3qUmN23gktIwTCYhTA/fmlKvM7mxNP5bSBut32eK3y8VVK1010ybbbDQPoJPNum5hFrELKCIHwiUchEVGKyTeaLfGrRdhTCrRJbI5fKtserxdRx34jjvRWnqeNU4i3IAi3CIt4h0IZloWNGbwsGaEAYZUo6lr+Mcr0unlmTro63hiHnstVr5GiaiYmRig1AUdT4yCl1onbrQvJQ5XOuyUBB8JFXF0zvFxSXTtdpOJKaQH2IVWJY2nBHq/bhnDXMFDIlfTjKNKJ9+52XvknvGiOyMCBNCKurp1u4k0rU+BDSVmPnsJ53oJw1wNXtUlIaap03oIgCC6I866Y1iIUIM6Bq2unceGqL3Zn0qIjzzXrM9Z5xgqIOO4wGCylgrVzpIBrSscoYx/SCfmk3UpFvdS0/FTCdVRMAty2cGskNmmAozLw8frxThxII+Q5lxJodU0TF2oQbNWP+Nf4SOF2fv50yVxiIjMsBUEQmoMBdDe8k1DZ3eMTxAgxxEQoQFwlytBG4ihF9aeOmZG1kTIaSOXwJCpJiTjvpohdgdD844/NwlOIOBD/YSZirkgtTmcQ7NTUJpZnjvn2aE68BUEQFDI9vjixu8mnWv+7hhgFSOvCgXUHehZHnvvrf0p3WYvrProcMgcyw7JRUlVepKpEUX2JL7PLOS6w9QauUdhLZrQ1CbYmVrhLvH5HLFlrXP3g6x9LEfG2ldnFuu+x7TR10LEuXPUlvYgDZQZ4Xd7oKQS+pkGzHK7t6DLAsR/lBmuP/J1KbCIIgtAcLAOWR5E6IqihEkX1I50DB5bO56hSy5pccwi58tFaYhKg3oqbHDDa/5uMIat4u+bSqSIUfc0aBjNVX+Km16+2W4mY105O4UmZtdYyKDlpq2LRHpFqkypI6cJTDmbGCrgml5ADIuaa3IKTY3BMhFsIpRrxFgRB8IKPrnY5lurEu7YIJVUObpLThQPrzuksjry0M0wtECm/6tfmuMtm0DI9vjpqE3BNTiHPIeKLa238odco7Ee+MWsWbE1twl0aGbCslBwZOJBuMkrKPBzI78Z3rx/w5nX93bQiDLm+gtfqtIc2G/n9LJFSQUEQhCYR552Y1F/nUn6lT7mhQY4YBVg6wCOcuAvtOjZFzsGu2mMSIO73V8tAoYh3AWJ3okmdyabMwoF8Qg60I+a1U0JwWhBtoP0PXkAPV7b/PEKR2EQQhGYR590AOVbby7W5b+rBzDnixN0o+dW+Bcd9Brc9gWVVwabItWRqzhgFSB+lmKz9Ad+SqJd+E+f8ui4xiTtnfV4ulN3DsvIlU3NuJ1ZSzDU+glaT0NfoploTa6DsQlzHxBcssYkgCEJryCSdTGzFEKkz21zTwXPuPOPj5Gpz6WehZKVCS1u3Tdqt/O9CYpNMDC8sb4tdrq/3WWcNJnozunwI3HI5VA20uh3b6jUSCjJzd6CASmySBu4A6n/EFcyXQZgYnfqOE4gpcLmdgJ5uWyoD3vvjq3HNkbNRi3sr7XJTCJ9+7XRbjKth2kp8ENXxuzsCUQZBEIQGiXbewycfTT+FGR267l49RBc1SzIwJ87x6brnaGv+RK9xp/cWqPl36kIt3xCA6WvJ3I3Oe/Ya533NGajoNSlNlHgzWCclSqy5F2tc0OHxIJDE+xGECJIg1IOP6KqYdBRvrQODmYvJTLcv3PwHcgwJMm/9S7sfxPqKt3DBAxBrQb6Pv4wgCNWihbrje7AWb75HTmfMqOvbSGmkzlsQhEaRapNA+ryJqb/VocNbAADCA3Tmi3pUJHLDv1jhxjgydjTzb3SG8+76x3K+D+uuQ89J/IBln2cR34P72GSxZnamyCuGW/7EFtpkc1zo4PfY9P00lgpmy7vVBW76fSyxiSAIDSPiHchYqsMAwPpT9goCjTcPJu+nvyCUYf5+oqHWqx6m77VuuDfX1W45Gk3gvG2/rMO/xSXkPM9EqJUwEa7/LzN/D0sbMyJ6BsCvALgD8Flm/oXZ498D4F8B+CEAbwD4GDP/To6+JI5N6v9zEoT6kPdNOOWcN6k1M54D8BEArwN4mYgeMfMXjMN+EsDvM/MPENGzAH4RwMdy9EdmxgiC0C7Maf9t80EArzHzl5j5LQAvAPjo7JiPAviX/c//FsBfI6Is+ZaItyAIjcLJ/9vhPQC+Ytx+vb/PegyrmslvAvhjiZ7wBN/Y5OvA9XdzdEQQhNPz/Ynbewm4fzJxm28joleM288z8/OJr5EEL/Fm5j+eqyOCIAg+MPMzhS/5VQBPGbff299nO+Z1InoA4A9DDVwmR2ITQRAEN14G8DQRvZ+IngDwLIBHs2MeAfjx/ucfA/CfmPMUTcskHUEQBAeY+Z6IPgngJahSwc8x86tE9BkArzDzIwD/AsC/JqLXAPwelMBngTJ9KAiCIAgZkdhEEAShQUS8BUEQGkTEWxAEoUFEvAVBEBpExFsQBKFBRLwFQRAaRMRbEAShQUS8BUEQGuT/AygW5L9VZG2TAAAAAElFTkSuQmCC\n", 48 | "text/plain": [ 49 | "
" 50 | ] 51 | }, 52 | "metadata": {}, 53 | "output_type": "display_data" 54 | }, 55 | { 56 | "data": { 57 | "image/png": "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\n", 58 | "text/plain": [ 59 | "
" 60 | ] 61 | }, 62 | "metadata": {}, 63 | "output_type": "display_data" 64 | } 65 | ], 66 | "source": [ 67 | "omega = 2*np.pi*200e12\n", 68 | "dl = 0.02 # grid size (units of L0, which defaults to 1e-6)\n", 69 | "eps_r = np.ones((200, 200)) # relative permittivity\n", 70 | "NPML = [15, 15] # number of pml grid points on x and y borders\n", 71 | "\n", 72 | "simulation = Simulation(omega, eps_r, dl, NPML, 'Ez')\n", 73 | "simulation.src[100, 100] = 1\n", 74 | "simulation.solve_fields()\n", 75 | "\n", 76 | "simulation.plt_abs(outline=False, cbar=True);\n", 77 | "simulation.plt_re(outline=False, cbar=True);" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "## Ridge waveguide" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": {}, 90 | "source": [ 91 | "This example demonstrates solving for the fields of a waveguide excited by a modal source." 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 7, 97 | "metadata": { 98 | "collapsed": true 99 | }, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "input power of 0.0016689050319357455 in W/L0\n" 106 | ] 107 | }, 108 | { 109 | "data": { 110 | "image/png": "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\n", 111 | "text/plain": [ 112 | "
" 113 | ] 114 | }, 115 | "metadata": {}, 116 | "output_type": "display_data" 117 | }, 118 | { 119 | "data": { 120 | "image/png": "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\n", 121 | "text/plain": [ 122 | "
" 123 | ] 124 | }, 125 | "metadata": {}, 126 | "output_type": "display_data" 127 | } 128 | ], 129 | "source": [ 130 | "omega = 2*np.pi*200e12\n", 131 | "dl = 0.01 # grid size (units of L0, which defaults to 1e-6)\n", 132 | "eps_r = np.ones((600, 200)) # relative permittivity\n", 133 | "eps_r[:,90:110] = 12.25 # set waveguide region\n", 134 | "NPML = [15, 15] # number of pml grid points on x and y borders\n", 135 | "\n", 136 | "simulation = Simulation(omega, eps_r, dl, NPML, 'Ez')\n", 137 | "simulation.add_mode(3.5, 'x', [20, 100], 60, scale=10)\n", 138 | "simulation.setup_modes()\n", 139 | "simulation.solve_fields()\n", 140 | "print('input power of {} in W/L0'.format(simulation.W_in))\n", 141 | "\n", 142 | "simulation.plt_re(outline=True, cbar=False);\n", 143 | "simulation.plt_abs(outline=True, cbar=False);" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "### Making an animation " 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "This demonstrates how one can generate an animation of the field." 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 9, 163 | "metadata": {}, 164 | "outputs": [ 165 | { 166 | "ename": "RuntimeError", 167 | "evalue": "Requested MovieWriter (ffmpeg) not available", 168 | "output_type": "error", 169 | "traceback": [ 170 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 171 | "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", 172 | "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/matplotlib/animation.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 169\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 170\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mavail\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 171\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 173 | "\u001b[0;31mKeyError\u001b[0m: 'ffmpeg'", 174 | "\nDuring handling of the above exception, another exception occurred:\n", 175 | "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", 176 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0manimation\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplt_base_ani\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msimulation\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfields\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"Ez\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcbar\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mNframes\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m40\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minterval\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m80\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mHTML\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0manimation\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_html5_video\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0;31m# animation.save('fields.gif', dpi=80, writer='imagemagick')\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 177 | "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/matplotlib/animation.py\u001b[0m in \u001b[0;36mto_html5_video\u001b[0;34m(self, embed_limit)\u001b[0m\n\u001b[1;32m 1347\u001b[0m \u001b[0;31m# We create a writer manually so that we can get the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1348\u001b[0m \u001b[0;31m# appropriate size for the tag\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1349\u001b[0;31m \u001b[0mWriter\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mwriters\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mrcParams\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'animation.writer'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1350\u001b[0m writer = Writer(codec='h264',\n\u001b[1;32m 1351\u001b[0m \u001b[0mbitrate\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrcParams\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'animation.bitrate'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 178 | "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/matplotlib/animation.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 171\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 172\u001b[0m raise RuntimeError(\n\u001b[0;32m--> 173\u001b[0;31m 'Requested MovieWriter ({}) not available'.format(name))\n\u001b[0m\u001b[1;32m 174\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 175\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 179 | "\u001b[0;31mRuntimeError\u001b[0m: Requested MovieWriter (ffmpeg) not available" 180 | ] 181 | } 182 | ], 183 | "source": [ 184 | "from matplotlib import animation, rc\n", 185 | "from IPython.display import HTML\n", 186 | "from fdfdpy.plot import plt_base_ani\n", 187 | "animation = plt_base_ani(simulation.fields[\"Ez\"], cbar=True, Nframes=40, interval=80)\n", 188 | "\n", 189 | "HTML(animation.to_html5_video())\n", 190 | "# animation.save('fields.gif', dpi=80, writer='imagemagick')" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": null, 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [] 199 | } 200 | ], 201 | "metadata": { 202 | "kernelspec": { 203 | "display_name": "Python 3", 204 | "language": "python", 205 | "name": "python3" 206 | }, 207 | "language_info": { 208 | "codemirror_mode": { 209 | "name": "ipython", 210 | "version": 3 211 | }, 212 | "file_extension": ".py", 213 | "mimetype": "text/x-python", 214 | "name": "python", 215 | "nbconvert_exporter": "python", 216 | "pygments_lexer": "ipython3", 217 | "version": "3.6.4" 218 | } 219 | }, 220 | "nbformat": 4, 221 | "nbformat_minor": 2 222 | } 223 | -------------------------------------------------------------------------------- /notebooks/Examples_nonlinear.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# fdfdpy test notebook" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## Import/setup" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "from fdfdpy import Simulation\n", 26 | "\n", 27 | "import matplotlib.pylab as plt\n", 28 | "import numpy as np\n", 29 | "import scipy.sparse as sp\n", 30 | "\n", 31 | "%load_ext autoreload\n", 32 | "%autoreload 2\n", 33 | "%matplotlib inline\n", 34 | "\n", 35 | "plt.style.use(['https://git.io/photons.mplstyle',\n", 36 | " 'https://git.io/photons-paper.mplstyle'])" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [ 44 | { 45 | "name": "stdout", 46 | "output_type": "stream", 47 | "text": [ 48 | "10.0\n", 49 | "16.68100537200059\n", 50 | "27.825594022071243\n", 51 | "46.41588833612777\n", 52 | "77.4263682681127\n", 53 | "129.1549665014884\n", 54 | "215.44346900318823\n", 55 | "359.38136638046257\n", 56 | "599.4842503189409\n", 57 | "1000.0\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "omega = 2*np.pi*200e12\n", 63 | "dl = 0.01\n", 64 | "eps_r = np.ones((600, 200))\n", 65 | "eps_r[:,80:120] = 12.25\n", 66 | "\n", 67 | "nl_region = np.zeros(eps_r.shape)\n", 68 | "nl_region[100:500, 80:120] = 1\n", 69 | "\n", 70 | "simulation = Simulation(omega, eps_r, dl, [15, 15], 'Ez')\n", 71 | "simulation.add_mode(3.5, 'x', [17, 100], 150)\n", 72 | "simulation.setup_modes()\n", 73 | "simulation.solve_fields()\n", 74 | "\n", 75 | "fld0 = simulation.fields['Ez'][20, 100]\n", 76 | "fld1 = simulation.fields['Ez'][580, 100]\n", 77 | "T_linear = fld1/fld0\n", 78 | "\n", 79 | "chi3 = 2.8*1e-18/simulation.L0**2\n", 80 | "kerr_nonlinearity = lambda e: 3*chi3*np.square(np.abs(e))\n", 81 | "dkerr_de = lambda e: 3*chi3*np.conj(e)\n", 82 | "\n", 83 | "srcval_vec = np.logspace(1, 3, 10)\n", 84 | "# srcval_vec = np.insert(srcval_vec,0,1e-3)\n", 85 | "pwr_vec = np.array([])\n", 86 | "T_vec = np.array([])\n", 87 | "for srcval in srcval_vec:\n", 88 | " print(srcval)\n", 89 | " simulation.setup_modes()\n", 90 | " simulation.src *= srcval\n", 91 | " simulation.solve_fields_nl(kerr_nonlinearity, nl_region,\n", 92 | " dnl_de=dkerr_de, timing=False, averaging=True,\n", 93 | " Estart=None, solver_nl='newton')\n", 94 | " fld0 = simulation.fields['Ez'][20, 100]\n", 95 | " fld1 = simulation.fields['Ez'][580, 100]\n", 96 | " T_vec = np.append(T_vec, fld1/fld0)\n", 97 | " pwr = simulation.flux_probe('x', [580, 100], 150)\n", 98 | " pwr_vec = np.append(pwr_vec, pwr)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "from fdfdpy.constants import *\n", 108 | "width = dl*40\n", 109 | "height = width\n", 110 | "Aeff = width*height # Assume square wg if extrapolated to 3D\n", 111 | "# n2 = 2.7e-14*1e-4/simulation.L0**2\n", 112 | "n2 = 3*chi3/(3e8/simulation.L0)/np.sqrt(12.25)/(EPSILON_0*simulation.L0)\n", 113 | "L = dl*400\n", 114 | "gamma_spm = (omega/3e8*simulation.L0)*n2/Aeff\n", 115 | "\n", 116 | "plt.figure(figsize=(4,3))\n", 117 | "plt.loglog(pwr_vec*height, -np.unwrap(np.angle(T_vec)-np.angle(T_linear))/np.pi, \"-o\", label=\"fdfd\")\n", 118 | "plt.loglog(pwr_vec*height, (pwr_vec*height)*L*gamma_spm/np.pi, \"-o\", label=r\"analytic: $n_2k_0/A_{eff}\\cdot P \\cdot L$\")\n", 119 | "plt.xlabel(\"waveguide power (W)\")\n", 120 | "plt.ylabel(\"nonlinear phase shift ($\\pi$)\")\n", 121 | "plt.title(\"Waveguide Kerr SPM\")\n", 122 | "plt.legend()\n", 123 | "plt.show()" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "3*chi3/(3e8/simulation.L0)/np.sqrt(12.25)/(EPSILON_0*simulation.L0)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 22, 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "data": { 142 | "text/plain": [ 143 | "2.7e-06" 144 | ] 145 | }, 146 | "execution_count": 22, 147 | "metadata": {}, 148 | "output_type": "execute_result" 149 | } 150 | ], 151 | "source": [ 152 | "2.7e-14*1e-4/simulation.L0**2" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [] 161 | } 162 | ], 163 | "metadata": { 164 | "kernelspec": { 165 | "display_name": "Python 3", 166 | "language": "python", 167 | "name": "python3" 168 | }, 169 | "language_info": { 170 | "codemirror_mode": { 171 | "name": "ipython", 172 | "version": 3 173 | }, 174 | "file_extension": ".py", 175 | "mimetype": "text/x-python", 176 | "name": "python", 177 | "nbconvert_exporter": "python", 178 | "pygments_lexer": "ipython3", 179 | "version": "3.6.5" 180 | } 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 2 184 | } 185 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup, find_packages 4 | 5 | with open('README.md') as f: 6 | readme = f.read() 7 | 8 | setup( 9 | name='fdfdpy', 10 | version='0.1.2', 11 | description='Electromagnetic Finite Difference Frequency Domain Solver', 12 | long_description=readme, 13 | long_description_content_type="text/markdown", 14 | author='Tyler Hughes, Momchil Minkov, Ian Williamson', 15 | author_email='tylerwhughes91@gmail.com', 16 | url='https://github.com/fancompute/fdfdpy', 17 | packages=find_packages(exclude=('tests', 'docs')), 18 | install_requires=[ 19 | 'pyMKL', 20 | 'numpy', 21 | 'scipy', 22 | 'matplotlib', 23 | 'progressbar' 24 | ], 25 | classifiers=[ 26 | "Programming Language :: Python :: 3", 27 | "License :: OSI Approved :: MIT License", 28 | "Operating System :: OS Independent", 29 | ], 30 | ) 31 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fancompute/fdfdpy/49d3682a9cface0e2ce32932f4dbfc36adff9fef/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_chi3.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from numpy import pi, ones, zeros, square, conj, logspace, array, append, unwrap, angle 4 | from numpy.testing import assert_allclose 5 | from fdfdpy import Simulation 6 | 7 | class Test_Chi3(unittest.TestCase): 8 | 9 | def test_chi3(self): 10 | """Tests whether we get a nonlinear phase shift (self phase modulation) which agrees with analytical predictions""" 11 | 12 | # Set simulation parameters 13 | n0 = 3.4 14 | omega = 2*pi*200e12 15 | dl = 0.01 16 | chi3 = 2.8E-18 17 | 18 | width = 1 # WG width 19 | L = 5 # WG length 20 | L_chi3 = 4 # WG nonlinear length 21 | 22 | # Convert to voxels 23 | width_voxels = int(width/dl) 24 | L_chi3_voxels = int(L_chi3/dl) 25 | Nx = int(L/dl) 26 | Ny = int(3.5*width/dl) 27 | 28 | # Setup 29 | eps_r = ones((Nx, Ny)) 30 | eps_r[:,int(Ny/2-width_voxels/2):int(Ny/2+width_voxels/2)] = square(n0) 31 | nl_region = zeros(eps_r.shape) 32 | nl_region[int(Nx/2-L_chi3_voxels/2):int(Nx/2+L_chi3_voxels/2), int(Ny/2-width_voxels/2):int(Ny/2+width_voxels/2)] = 1 33 | simulation = Simulation(omega, eps_r, dl, [15, 15], 'Ez') 34 | simulation.add_mode(n0, 'x', [17, int(Ny/2)], width_voxels*3) 35 | simulation.setup_modes() 36 | simulation.solve_fields() 37 | 38 | # Probe field from linear simulation to get phase 39 | fld0 = simulation.fields['Ez'][20, int(Ny/2)] 40 | fld1 = simulation.fields['Ez'][Nx-20, int(Ny/2)] 41 | T_linear = fld1/fld0 42 | 43 | # Set nonlinear functions 44 | kerr_nonlinearity = lambda e: 3*chi3/square(simulation.L0)*square(abs(e)) 45 | dkerr_de = lambda e: 3*chi3/square(simulation.L0)*conj(e) 46 | 47 | # Sweep source power and record nonlinear phase accumulation 48 | srcval_vec = logspace(1, 3, 3) 49 | pwr_vec = array([]) 50 | T_vec = array([]) 51 | for srcval in srcval_vec: 52 | simulation.setup_modes() 53 | simulation.src *= srcval 54 | simulation.solve_fields_nl(kerr_nonlinearity, nl_region, 55 | dnl_de=dkerr_de, timing=False, averaging=True, 56 | Estart=None, solver_nl='newton') 57 | fld0 = simulation.fields['Ez'][20, int(Ny/2)] 58 | fld1 = simulation.fields['Ez'][Nx-20, int(Ny/2)] 59 | T_vec = append(T_vec, fld1/fld0) 60 | pwr = simulation.flux_probe('x', [Nx-20, int(Ny/2)], width_voxels*3) 61 | pwr_vec = append(pwr_vec, pwr) 62 | 63 | # Analytically calculate the expected nonlinear phase accumulation 64 | n2 = 12*square(pi)*chi3*1e4/square(n0) 65 | n2 *= 1e-4/square(simulation.L0) 66 | 67 | width = dl*width_voxels 68 | height = width 69 | Aeff = width*height 70 | 71 | L = dl*L_chi3_voxels 72 | gamma_spm = (omega/299792458*simulation.L0)*n2/Aeff 73 | 74 | P = pwr_vec*height # Power 75 | Phi_fdfd = -unwrap(angle(T_vec)-angle(T_linear))/pi # Nonlinear phase in FDFD 76 | Phi_analytic = (pwr_vec*height)*L*gamma_spm/pi # Analytic nonlinear phase 77 | 78 | # If our simulation is correct, these values should be equal 79 | assert_allclose(Phi_fdfd, Phi_analytic, rtol=1e-3) 80 | 81 | 82 | if __name__ == '__main__': 83 | unittest.main() 84 | -------------------------------------------------------------------------------- /tests/test_flux.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | 4 | from numpy import pi, ones 5 | from numpy.testing import assert_allclose 6 | from fdfdpy import Simulation 7 | 8 | 9 | class Test_Flux(unittest.TestCase): 10 | 11 | def test_flux(self): 12 | """Tests whether we can reduce the mesh resolution and get the same flux_probe output""" 13 | 14 | omega = 2*pi*200e12 15 | dl = 0.01 16 | eps_r = ones((300, 100)) 17 | eps_r[:, 40:60] = 12.25 18 | NPML = [15, 15] 19 | 20 | simulation1 = Simulation(omega, eps_r, dl, NPML, 'Ez') 21 | simulation1.add_mode(3.5, 'x', [20, 50], 60, scale=1) 22 | simulation1.setup_modes() 23 | simulation1.solve_fields() 24 | flux1 = simulation1.flux_probe('x', [150, 50], 60) 25 | 26 | omega = 2*pi*200e12 27 | dl = 0.005 28 | eps_r = ones((600, 200)) 29 | eps_r[:,80:120] = 12.25 30 | NPML = [15, 15] 31 | simulation2 = Simulation(omega, eps_r, dl, NPML, 'Ez') 32 | simulation2.add_mode(3.5, 'x', [20, 100], 120, scale=1) 33 | simulation2.setup_modes() 34 | simulation2.solve_fields() 35 | flux2 = simulation2.flux_probe('x', [300, 100], 120) 36 | 37 | assert_allclose(flux1, flux2, rtol=1e-3) 38 | 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /tests/test_linear.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fancompute/fdfdpy/49d3682a9cface0e2ce32932f4dbfc36adff9fef/tests/test_linear.py -------------------------------------------------------------------------------- /tests/test_modes.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fancompute/fdfdpy/49d3682a9cface0e2ce32932f4dbfc36adff9fef/tests/test_modes.py -------------------------------------------------------------------------------- /tests/test_nonlinear.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fancompute/fdfdpy/49d3682a9cface0e2ce32932f4dbfc36adff9fef/tests/test_nonlinear.py -------------------------------------------------------------------------------- /tests/test_nonlinear_solvers.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import matplotlib.pylab as plt 5 | from numpy.testing import assert_allclose 6 | 7 | from fdfdpy import Simulation 8 | 9 | 10 | class Test_NLSolve(unittest.TestCase): 11 | 12 | def test_born_newton(self): 13 | """Tests whether born and newton methods get the same result""" 14 | 15 | n0 = 3.4 16 | omega = 2*np.pi*200e12 17 | dl = 0.01 18 | chi3 = 2.8E-18 19 | 20 | width = 1 21 | L = 5 22 | L_chi3 = 4 23 | 24 | width_voxels = int(width/dl) 25 | L_chi3_voxels = int(L_chi3/dl) 26 | 27 | Nx = int(L/dl) 28 | Ny = int(3.5*width/dl) 29 | 30 | eps_r = np.ones((Nx, Ny)) 31 | eps_r[:, int(Ny/2-width_voxels/2):int(Ny/2+width_voxels/2)] = np.square(n0) 32 | 33 | nl_region = np.zeros(eps_r.shape) 34 | nl_region[int(Nx/2-L_chi3_voxels/2):int(Nx/2+L_chi3_voxels/2), int(Ny/2-width_voxels/2):int(Ny/2+width_voxels/2)] = 1 35 | 36 | simulation = Simulation(omega, eps_r, dl, [15, 15], 'Ez') 37 | simulation.add_mode(n0, 'x', [17, int(Ny/2)], width_voxels*3) 38 | simulation.setup_modes() 39 | simulation.add_nl(chi3, nl_region, eps_scale=True, eps_max=np.max(eps_r)) 40 | 41 | srcval_vec = np.logspace(1, 3, 3) 42 | pwr_vec = np.array([]) 43 | T_vec = np.array([]) 44 | for srcval in srcval_vec: 45 | simulation.setup_modes() 46 | simulation.src *= srcval 47 | 48 | # Newton 49 | simulation.solve_fields_nl(solver_nl='newton') 50 | E_newton = simulation.fields["Ez"] 51 | 52 | # Born 53 | simulation.solve_fields_nl(solver_nl='born') 54 | E_born = simulation.fields["Ez"] 55 | 56 | # More solvers (if any) should be added here with corresponding calls to assert_allclose() below 57 | 58 | assert_allclose(E_newton, E_born, rtol=1e-3) 59 | 60 | if __name__ == '__main__': 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /tests/test_simulation.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import numpy as np 3 | 4 | from fdfdpy import Simulation 5 | 6 | class Test_Simulation(unittest.TestCase): 7 | """ Tests the simulation object for various functionalities """ 8 | 9 | # this function gets run automatically at beginning of testing. 10 | def setUp(self): 11 | 12 | # the 'good' inputs 13 | Nx = 100 14 | Ny = 50 15 | self.omega = 100 16 | self.eps_r = np.ones((Nx, Ny)) 17 | self.dl = 0.001 18 | self.NPML = [10, 10] 19 | self.pol = 'Hz' 20 | self.L0 = 1e-4 21 | 22 | """ all of the functions below get run by the unittest module as long as the 23 | function names start with 'test' """ 24 | 25 | 26 | """ These functions ensuring that an error is thrown 27 | when passing certain arguments to Simulation """ 28 | 29 | def test_freq(self): 30 | 31 | # negative frequency 32 | with self.assertRaises(ValueError): 33 | Simulation(-self.omega, self.eps_r, self.dl, self.NPML, self.pol) 34 | 35 | # list of frequencies 36 | with self.assertRaises(ValueError): 37 | Simulation([100, 200, 300], self.eps_r, self.dl, self.NPML, self.pol) 38 | 39 | def test_eps(self): 40 | 41 | # negative epsilon 42 | with self.assertRaises(ValueError): 43 | Simulation(self.omega, -self.eps_r, self.dl, self.NPML, self.pol) 44 | 45 | # list epsilon instead of numpy array 46 | with self.assertRaises(ValueError): 47 | Simulation(self.omega, list(self.eps_r), self.dl, self.NPML, self.pol) 48 | 49 | def test_dl(self): 50 | 51 | # negative dl 52 | with self.assertRaises(ValueError): 53 | Simulation(self.omega, self.eps_r, -self.dl, self.NPML, self.pol) 54 | 55 | # list of dl 56 | with self.assertRaises(ValueError): 57 | Simulation(self.omega, self.eps_r, [1e-4, 1e-5], self.NPML, self.pol) 58 | 59 | def test_NPML(self): 60 | 61 | # NPML a number 62 | with self.assertRaises(ValueError): 63 | Simulation(self.omega, self.eps_r, self.dl, 10, self.pol) 64 | 65 | # NPML too many elements 66 | with self.assertRaises(ValueError): 67 | Simulation(self.omega, self.eps_r, self.dl, [10, 10, 10], self.pol) 68 | 69 | # NPML larger than domain 70 | with self.assertRaises(ValueError): 71 | Simulation(self.omega, self.eps_r, self.dl, [200, 200], self.pol) 72 | 73 | def test_pol(self): 74 | 75 | # polarization not a string 76 | with self.assertRaises(ValueError): 77 | Simulation(self.omega, self.eps_r, self.dl, self.NPML, 5) 78 | 79 | # polarization not the right string 80 | with self.assertRaises(ValueError): 81 | Simulation(self.omega, self.eps_r, self.dl, self.NPML, 'WrongPolarization') 82 | 83 | 84 | if __name__ == '__main__': 85 | main() 86 | --------------------------------------------------------------------------------