def testLoadFromDatabase(self): wavelength = 0.1879 # Should load from Johnson nk table source = Source(wavelength=wavelength) Ag = Material('Ag', source=source) n_desired = 1.07 + 1.212j n_observed = Ag.n assertAlmostEqual(n_desired, n_observed, absoluteTolerance=1e-3) source.wavelength = 0.2262 n_desired = 1.26 + 1.344j n_observed = Ag.n assertAlmostEqual(n_desired, n_observed, absoluteTolerance=1e-3)
def testaTEM(self): aTEActual = complexArray([-0.39073, 0.920505, 0]) aTMActual = complexArray([0.50137, 0.21282, -0.838671]) (aTECalculated, aTMCalculated) = self.source.aTE, self.source.aTM assertAlmostEqual(aTEActual, aTECalculated, self.absoluteTolerance, self.relativeTolerance, "Oblique incidence TE vector wrong") assertAlmostEqual(aTMActual, aTMCalculated, self.absoluteTolerance, self.relativeTolerance, "Oblique incidence TM vector wrong") ATEMActual = np.vstack((aTEActual, aTMActual)) ATEMCalculated = self.source.ATEM assertAlmostEqual(ATEMActual, ATEMCalculated, self.absoluteTolerance, self.relativeTolerance, "Oblique incidence TM vector wrong") # Important corner case where the cross product fails aTEActual = complexArray([0, 1, 0]) aTMActual = complexArray([1, 0, 0]) zeroAngleSource = Source() (aTECalculated, aTMCalculated) = zeroAngleSource.aTE, zeroAngleSource.aTM assertAlmostEqual(aTEActual, aTECalculated, self.absoluteTolerance, self.relativeTolerance, "Near-normal Incidence TE vector wrong") assertAlmostEqual(aTMActual, aTMCalculated, self.absoluteTolerance, self.relativeTolerance, "Near-normal incidence TM vector wrong")
def setUp(self): self.absoluteTolerance = 1e-5 self.relativeTolerance = 1e-4 wavelength = 0.02 theta = 60 * deg phi = 30 * deg pTEM = 1 / sqrt(2) * complexArray([1, 1j]) reflectionLayer = Layer(er=2, ur=1) self.source = Source(wavelength, theta, phi, pTEM, reflectionLayer)
def testAvoidDiscontinuities(self): source = Source(wavelength=0.495) silicon = Material(filename='main/Si/Aspnes.yml', source=source) n_desired = 4.325778947368422 + 0.07380526315789473j n_observed = silicon.n assertAlmostEqual(n_observed, n_desired, errorMessage="material: testnk: n25", absoluteTolerance=1e-6) source.wavelength = 0.496 n_desired = 4.319492753623189 + 0.07293719806763285j n_observed = silicon.n assertAlmostEqual(n_observed, n_desired, errorMessage="material: testnk: n26", absoluteTolerance=1e-6)
def setUp(self): self.absoluteTolerance = 1e-4 self.relativeTolerance = 1e-3 devicePermittivityCellData = np.transpose( np.loadtxt(testLocation + '/triangleData.csv', delimiter=',')) devicePermeabilityCellData = 1 + 0 * devicePermittivityCellData reflectionLayer = Layer(er=2.0, ur=1.0) transmissionLayer = Layer(er=9.0, ur=1.0) # NOTE: t1 AND t2 MUST BE NORMALIZED BY MULTIPLYING BY k0, OTHERWISE THIS WILL NOT WORK, AS # EVERYTHING WAS FORMULATED IN TERMS OF NORMALIZED WAVEVECTORS. I DON'T KNOW OF AN ELEGANT WAY # TO DO THIS OTHER THAN REQUIRING A CRYSTAL TO HAVE A SOURCE AS THE INPUT. I DON'T KNOW OF # AN EASY WAY TO FIX THIS. I'M GOING TO FUDGE IT FOR NOW. wavelength = 2 k0 = 2 * pi / wavelength theta = 60 * deg phi = 30 * deg pTEM = 1 / sqrt(2) * complexArray([1, 1j]) source = Source(wavelength=wavelength, theta=theta, phi=phi, pTEM=pTEM, layer=reflectionLayer) t1, t2 = complexArray([1.75, 0, 0]), complexArray([0, 1.5, 0]) thicknessLayer1 = 0.5 # should be 0.5 thicknessLayer2 = 0.3 # should be 0.3 numberHarmonics = (3, 3) deviceCrystal = Crystal(devicePermittivityCellData, devicePermeabilityCellData, t1, t2) layer1 = Layer(crystal=deviceCrystal, L=thicknessLayer1, numberHarmonics=numberHarmonics) layer2 = Layer(er=6.0, ur=1.0, L=thicknessLayer2) layerStack = LayerStack(reflectionLayer, layer1, layer2, transmissionLayer) self.solver = Solver(layerStack, source, numberHarmonics)
def setUpClass(self): # NOTE - self here refers to class self.absoluteTolerance = 1e-3 self.relativeTolerance = 1e-3 deg = pi / 180 wavelength = 2 theta = 60 * deg phi = 30 * deg pTEM = 1 / sqrt(2) * complexArray([1, 1j]) erReflectionRegion = 2 urReflectionRegion = 1 erTransmissionRegion = 9 urTransmissionRegion = 1 erDeviceRegion = 6 urDeviceRegion = 1 thicknessLayer1 = 0.5 thicknessLayer2 = 0.3 numberHarmonicsX = 3 numberHarmonicsY = 3 reflectionLayer = Layer(erReflectionRegion, urReflectionRegion) transmissionLayer = Layer(erTransmissionRegion, urTransmissionRegion) layer1 = Layer(erDeviceRegion, urDeviceRegion, thicknessLayer1) layer1.homogenous = False layer2 = Layer(erDeviceRegion, urDeviceRegion, thicknessLayer2) self.layerStack = LayerStack(reflectionLayer, layer1, layer2, transmissionLayer) self.source = Source(wavelength, theta, phi, pTEM, reflectionLayer) self.numberHarmonics = (numberHarmonicsX, numberHarmonicsY) erConvolutionMatrixLayer1 = numpyArrayFromFile( testLocation + "/matrixDataOblique/layer1/erConvolutionData.txt") urConvolutionMatrixLayer1 = complexIdentity(9) erConvolutionMatrixLayer2 = erDeviceRegion * complexIdentity(9) urConvolutionMatrixLayer2 = complexIdentity(9) # This is a bit of a hack, but that's good for test purposes. self.layerStack.internalLayer[0].er = erConvolutionMatrixLayer1 self.layerStack.internalLayer[0].ur = urConvolutionMatrixLayer1 self.layerStack.internalLayer[1].er = erConvolutionMatrixLayer2 self.layerStack.internalLayer[1].ur = urConvolutionMatrixLayer2 self.Kx = np.diag( complexArray([ 2.2035, 1.0607, -0.0822, 2.2035, 1.0607, -0.0822, 2.2035, 1.0607, -0.0822 ])) self.Ky = np.diag( complexArray([ 1.9457, 1.9457, 1.9457, 0.6124, 0.6124, 0.6124, -0.7210, -0.7210, -0.7210 ])) self.KzReflectionRegion = numpyArrayFromFile( testLocation + "/matrixDataOblique/reflectionRegion/KzReflectionRegion.txt") self.KzTransmissionRegion = np.diag( complexArray([ 0.5989, 2.0222, 2.2820, 1.9415, 2.7386, 2.9357, 1.9039, 2.7121, 2.9109 ])) self.KzFreeSpace = numpyArrayFromFile( testLocation + "/matrixDataOblique/freeSpace/KzFreeSpace.txt") self.QFreeSpace = numpyArrayFromFile( testLocation + "/matrixDataOblique/freeSpace/QFreeSpace.txt") self.WFreeSpace = complexIdentity(18) self.LambdaFreeSpace = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/freeSpace/LambdaFreeSpace.txt") self.VFreeSpace = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/freeSpace/VFreeSpace.txt") self.S11Transparent = complexZeros((18, 18)) self.S22Transparent = complexZeros((18, 18)) self.S21Transparent = complexIdentity(18) self.S12Transparent = complexIdentity(18) self.PLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/PLayer1.txt") self.QLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/QLayer1.txt") self.OmegaSquaredLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/OmegaSquaredLayer1.txt") self.LambdaLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/LambdaLayer1.txt") # NOTE - THE LAYER 1 VALUES ARE MODIFIED SO THAT ELEMENTS 7, 11, 12, AND 16 ALONG THE MAIN # DIAGONAL OF THE EIGENVALUE MATRIX ARE THEIR OWN CONJUGATE. THIS IS A NUMERICAL ERROR ISSUE # THAT I DON'T KNOW HOW TO RESOLVE AND I DON'T THINK IT SHOULD HAVE ANY PHYSICAL CONSEQUENCES. # SO I HAVE MODIFIED THE X AND V MATRICES. PHYSICALLY, self.VLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/VLayer1.txt") self.ALayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/ALayer1.txt") self.BLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/BLayer1.txt") self.XLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/XLayer1.txt") self.WLayer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/WLayer1.txt") self.S11Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/S11Layer1.txt") self.S12Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/S12Layer1.txt") self.S21Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/S21Layer1.txt") self.S22Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/S22Layer1.txt") self.SLayer1 = complexArray([[self.S11Layer1, self.S12Layer1], [self.S21Layer1, self.S22Layer1]]) self.SGlobal11Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/SGlobal11Layer1.txt") self.SGlobal12Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/SGlobal12Layer1.txt") self.SGlobal21Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/SGlobal21Layer1.txt") self.SGlobal22Layer1 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer1/SGlobal22Layer1.txt") self.SGlobalLayer1 = complexArray( [[self.SGlobal11Layer1, self.SGlobal12Layer1], [self.SGlobal21Layer1, self.SGlobal22Layer1]]) self.PLayer2 = numpyArrayFromFile( testLocation + "/matrixDataOblique/layer2/PLayer2.txt") self.QLayer2 = numpyArrayFromFile( testLocation + "/matrixDataOblique/layer2/QLayer2.txt") self.OmegaSquaredLayer2 = numpyArrayFromFile( testLocation + "/matrixDataOblique/layer2/OmegaSquaredLayer2.txt") self.WLayer2 = complexIdentity(18) self.LambdaLayer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/LambdaLayer2.txt") self.VLayer2 = np.loadtxt( testLocation + "/matrixDataOblique/layer2/VLayer2MYSELF.csv", dtype=np.cdouble ) # This is to rearrange the eigenvalue columns so that they display properly. self.ALayer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/ALayer2.txt") self.BLayer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/BLayer2.txt") self.XLayer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/XLayer2.txt") self.S11Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/S11Layer2.txt") self.S12Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/S12Layer2.txt") self.S21Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/S21Layer2.txt") self.S22Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/S22Layer2.txt") self.SLayer2 = complexArray([[self.S11Layer2, self.S12Layer2], [self.S21Layer2, self.S22Layer2]]) self.DLayer12 = np.loadtxt(testLocation + '/matrixDataOblique/layer2/D12.csv', dtype=np.cdouble) self.FLayer12 = np.loadtxt(testLocation + '/matrixDataOblique/layer2/F12.csv', dtype=np.cdouble) self.SGlobal11Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/SGlobal11Layer2.txt") self.SGlobal12Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/SGlobal12Layer2.txt") self.SGlobal21Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/SGlobal21Layer2.txt") self.SGlobal22Layer2 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/layer2/SGlobal22Layer2.txt") self.SGlobalLayer2 = complexArray( [[self.SGlobal11Layer2, self.SGlobal12Layer2], [self.SGlobal21Layer2, self.SGlobal22Layer2]]) self.QReflectionRegion = numpyArrayFromFile( testLocation + "/matrixDataOblique/reflectionRegion/QReflectionRegion.txt") self.LambdaReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/LambdaReflectionRegion.txt") self.WReflectionRegion = complexIdentity(18) self.VReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/VReflectionRegion.txt") self.LambdaReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/LambdaReflectionRegion.txt") self.AReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/AReflectionRegion.txt") self.BReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/BReflectionRegion.txt") self.S11ReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/S11ReflectionRegion.txt") self.S12ReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/S12ReflectionRegion.txt") self.S21ReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/S21ReflectionRegion.txt") self.S22ReflectionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/reflectionRegion/S22ReflectionRegion.txt") self.SReflectionRegion = complexArray( [[self.S11ReflectionRegion, self.S12ReflectionRegion], [self.S21ReflectionRegion, self.S22ReflectionRegion]]) self.QTransmissionRegion = numpyArrayFromFile( testLocation + "/matrixDataOblique/transmissionRegion/QTransmissionRegion.txt") self.LambdaTransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/LambdaTransmissionRegion.txt" ) self.WTransmissionRegion = complexIdentity(18) self.VTransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/VTransmissionRegion.txt") self.LambdaTransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/LambdaTransmissionRegion.txt" ) self.ATransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/ATransmissionRegion.txt") self.BTransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/BTransmissionRegion.txt") self.S11TransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/S11TransmissionRegion.txt") self.S12TransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/S12TransmissionRegion.txt") self.S21TransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/S21TransmissionRegion.txt") self.S22TransmissionRegion = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/transmissionRegion/S22TransmissionRegion.txt") self.STransmissionRegion = complexArray( [[self.S11TransmissionRegion, self.S12TransmissionRegion], [self.S21TransmissionRegion, self.S22TransmissionRegion]]) # Overall global scattering matrices self.SGlobal11 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/SGlobal11.txt") self.SGlobal12 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/SGlobal12.txt") self.SGlobal21 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/SGlobal21.txt") self.SGlobal22 = numpyArrayFromSeparatedColumnsFile( testLocation + "/matrixDataOblique/SGlobal22.txt") self.SGlobal = complexArray([[self.SGlobal11, self.SGlobal12], [self.SGlobal21, self.SGlobal22]]) self.transparentSMatrix = complexZeros((2, 2, 18, 18)) self.transparentSMatrix[0, 1] = complexIdentity(18) self.transparentSMatrix[1, 0] = complexIdentity(18) self.rx = complexArray([ -0.0187 - 0.0155j, 0.0486 - 0.0467j, 0.0016 + 0.0012j, 0.0324 - 0.0229j, -0.1606 - 0.0348j, -0.0089 + 0.0156j, 0.0020 + 0.0105j, 0.0076 + 0.0187j, -0.0027 - 0.0129j ]) self.ry = complexArray([ -0.0077 - 0.0106j, 0.0184 + 0.0323j, -0.0267 - 0.0070j, -0.0286 + 0.0472j, 0.2335 + 0.0138j, 0.0243 + 0.0164j, 0.0435 - 0.018j, 0.0183 + 0.0146j, -0.0062 + 0.0011j ]) self.rT = np.hstack((self.rx, self.ry)) self.rz = complexArray([ 0.0213 - 0.0218j, -0.0078 + 0.0512j, 0.0103 - 0.0388j, 0.0120 + 0.0300j, -0.0386 - 0.0403j, 0.0123 + 0.0069j, -0.0197 - 0.0147j, -0.0087 + 0.0157j, 0.0039 + 0.0002j ]) self.tx = complexArray([ 0.0015 - 0.0016j, -0.0583 + 0.0256j, -0.0245 - 0.0098j, 0.0060 + 0.0210j, 0.3040 + 0.0664j, -0.0054 - 0.0632j, -0.0123 - 0.0262j, -0.0323 - 0.0534j, 0.0169 + 0.0455j ]) self.ty = complexArray([ -0.0024 + 0.0011j, 0.0356 + 0.0282j, -0.0230 - 0.0071j, 0.0610 - 0.0011j, 0.0523 - 0.2913j, -0.0645 - 0.0027j, -0.0170 - 0.0165j, -0.0420 + 0.0298j, 0.0258 - 0.0234j ]) self.tT = np.hstack((self.tx, self.ty)) self.tz = complexArray([ 0.0023 + 0.0021j, -0.0036 - 0.0406j, 0.0187 + 0.0057j, -0.0261 - 0.0235j, -0.1294 + 0.0394j, 0.0133 - 0.0012j, 0.0078 + 0.0241j, 0.0014 + 0.0288j, 0.0069 - 0.0045j ]) self.R = np.array([[0, 0, 0], [0, 0.0848, 0.0011], [0, 0.0025, 0.0004]]) self.T = np.array([[0, 0.0149, 0.0055], [0.0222, 0.7851, 0.0283], [0.0053, 0.0348, 0.0150]]) self.R = np.transpose(self.R) self.T = np.transpose(self.T) self.RTot = 0.088768 self.TTot = 0.91123
def setUpClass(self): deg = pi / 180 self.absoluteTolerance = 1e-4 self.relativeTolerance = 1e-3 self.theta = 57 * deg self.phi = 23 * deg self.pTE = 1 self.pTM = 1j self.wavelength = 2.7 erReflectionRegion = 1.4 urReflectionRegion = 1.2 erTransmissionRegion = 1.8 urTransmissionRegion = 1.6 erLayer1 = 2.0 urLayer1 = 1.0 erLayer2 = 1.0 urLayer2 = 3.0 reflectionLayer = Layer(erReflectionRegion, urReflectionRegion) self.source = Source(wavelength=self.wavelength, theta=self.theta, phi=self.phi, pTEM=[self.pTE, self.pTM], layer=reflectionLayer) thicknessLayer1 = 0.25 * self.source.wavelength thicknessLayer2 = 0.5 * self.source.wavelength transmissionLayer = Layer(erTransmissionRegion, urTransmissionRegion) layer1 = Layer(er=erLayer1, ur=urLayer1, L=thicknessLayer1) layer2 = Layer(er=erLayer2, ur=urLayer2, L=thicknessLayer2) self.layerStack = LayerStack(reflectionLayer, layer1, layer2, transmissionLayer) self.Kx = reflectionLayer.n * sin(self.theta) * cos(self.phi) self.Ky = reflectionLayer.n * sin(self.theta) * sin(self.phi) self.layerStack.gapLayer.er = 1 + sq(self.Kx) + sq(self.Ky) self.layerStack.gapLayer.ur = 1 self.KzReflectionRegion = 0.705995 self.KzTransmissionRegion = 1.3032 self.KzLayer1 = 0.9046 self.KzLayer2 = 1.3485 self.ExReflected = 0.0519 - 0.2856j self.EyReflected = -0.4324 + 0.0780j self.EzReflected = 0.1866 + 0.3580j self.ExyzReflected = complexArray( [self.ExReflected, self.EyReflected, self.EzReflected]) self.ExTransmitted = -0.0101 + 0.3577j self.EyTransmitted = 0.4358 - 0.0820j self.EzTransmitted = -0.1343 - 0.2480j self.ExyzTransmitted = complexArray( [self.ExTransmitted, self.EyTransmitted, self.EzTransmitted]) self.rx = 0.0519 - 0.2856j self.ry = -0.4324 + 0.0780j self.rz = 0.1866 + 0.3580j self.tx = -0.0101 + 0.3577j self.ty = 0.4358 - 0.0820j self.tz = -0.1343 - 0.2480j self.R = 0.4403 self.T = 0.5597 self.KzGap = 1 self.WGap = complexIdentity(2) self.VGap = complexArray([[0 - 0.4250j, 0 - 1.1804j], [0 + 2.0013j, 0 + 0.4250j]]) self.ALayer1 = complexArray([[2.0049, -0.0427], [-0.0427, 2.0873]]) self.BLayer1 = complexArray([[-0.0049, 0.0427], [0.0427, -0.0873]]) self.XLayer1 = complexArray([[0.1493 + 0.9888j, 0 + 0j], [0 + 0j, 0.1493 + 0.9888j]]) self.DLayer1 = complexArray([[2.0057 - 0.0003j, -0.0445 + 0.0006j], [-0.0445 + 0.0006j, 2.0916 - 0.0013j]]) self.ALayer2 = complexArray([[3.8324, 0.2579], [0.2579, 3.3342]]) self.BLayer2 = complexArray([[-1.8324, -0.2579], [-0.2579, -1.3342]]) self.XLayer2 = complexArray([[-0.4583 - 0.8888j, 0 + 0j], [0 + 0j, -0.4583 - 0.8888j]]) self.DLayer2 = complexArray([[4.3436 - 0.7182j, 0.3604 - 0.1440j], [0.3604 - 0.1440j, 3.6475 - 0.4401j]]) self.S11Layer1 = complexArray([[0.0039 - 0.0006j, -0.0398 + 0.0060j], [-0.0398 + 0.0060j, 0.0808 - 0.0121j]]) self.S11Layer2 = complexArray([[0.6997 - 0.2262j, 0.0517 - 0.0014j], [0.0517 - 0.0014j, 0.5998 - 0.2235j]]) self.S12Layer1 = complexArray([[0.1490 + 0.9880j, 0.0005 + 0.0017j], [0.0005 + 0.0017j, 0.1480 + 0.9848j]]) self.S12Layer2 = complexArray([[-0.2093 - 0.6406j, 0.0311 + 0.0390j], [0.0311 + 0.0390j, -0.2693 - 0.7160j]]) self.S21Layer1 = complexArray([[0.1490 + 0.9880j, 0.0005 + 0.0017j], [0.0005 + 0.0017j, 0.1480 + 0.9848j]]) self.S21Layer2 = complexArray([[-0.2093 - 0.6406j, 0.0311 + 0.0390j], [0.0311 + 0.0390j, -0.2693 - 0.7160j]]) self.S22Layer1 = complexArray([[0.0039 - 0.0006j, -0.0398 + 0.0060j], [-0.0398 + 0.0060j, 0.0808 - 0.0121j]]) self.S22Layer2 = complexArray([[0.6997 - 0.2262j, 0.0517 - 0.0014j], [0.0517 - 0.0014j, 0.5998 - 0.2235j]]) self.SLayer1 = complexArray([[self.S11Layer1, self.S12Layer1], [self.S21Layer1, self.S22Layer1]]) self.SLayer2 = complexArray([[self.S11Layer2, self.S12Layer2], [self.S21Layer2, self.S22Layer2]]) self.transparentSMatrix = complexZeros((2, 2, 2, 2)) self.transparentSMatrix[1, 0] = complexIdentity(2) self.transparentSMatrix[0, 1] = complexIdentity(2) self.SReflectionRegion = complexZeros((2, 2, 2, 2)) self.SReflectionRegion[0, 0] = complexArray([[-0.0800, 0.0761], [0.0761, -0.2269]]) self.SReflectionRegion[0, 1] = complexArray([[1.0800, -0.0761], [-0.0761, 1.2269]]) self.SReflectionRegion[1, 0] = complexArray([[0.9200, 0.0761], [0.0761, 0.7731]]) self.SReflectionRegion[1, 1] = complexArray([[0.0800, -0.0761], [-0.0761, 0.2269]]) self.STransmissionRegion = complexZeros((2, 2, 2, 2)) self.STransmissionRegion[0, 0] = complexArray([[0.2060, 0.0440], [0.0440, 0.1209]]) self.STransmissionRegion[0, 1] = complexArray([[0.7940, -0.0440], [-0.0440, 0.8791]]) self.STransmissionRegion[1, 0] = complexArray([[1.2060, 0.0440], [0.0440, 1.1209]]) self.STransmissionRegion[1, 1] = complexArray([[-0.2060, -0.0440], [-0.0440, -0.1209]])
t1 = designWavelength / 4 / n1 t2 = designWavelength / 4 / n2 reflectionLayer = Layer(n=1) transmissionLayer = Layer(n=n1) layer0 = Layer(n=n1, L=t1) layer1 = Layer(n=n2, L=t2) layer2 = Layer(n=n1, L=t1) layer3 = Layer(n=n2, L=t2) layer4 = Layer(n=n1, L=t1) layer5 = Layer(n=n2, L=t2) layer6 = Layer(n=n1, L=t1) layer7 = Layer(n=n2, L=t2) layer8 = Layer(n=n1, L=t1) layer9 = Layer(n=n2, L=t2) layer10 = Layer(n=n1, L=t1) stack = LayerStack(reflectionLayer, layer0, layer1, layer2, layer3, layer4, layer5, layer6, layer7, layer8, layer9, layer10, transmissionLayer) source = Source(wavelength=designWavelength) print("Solving system...") TMMSolver = Solver(stack, source, (1, 1)) wavelengths = np.arange(startWavelength, stopWavelength + stepWavelength, stepWavelength) TMMSolver.Solve(wavelengths=wavelengths) #Plotter.plotEllipsometrySpectra(TMMSolver1.results) Plotter.plotRTSpectra(TMMSolver.results) plt.show()
def setUpClass(cls): source = Source(wavelength=1) cls.silicon = Material(filename='main/Si/Schinke.yml', source=source)
def test_extract_dispersion_formula_1(self): src = Source(wavelength=0.5) SiO2 = Material(filename='main/SiO2/Radhakrishnan-o.yml', source=src) n_desired = 1.548755 n_actual = SiO2.n assertAlmostEqual(n_actual, n_desired, absoluteTolerance=1e-5)
def test_extract_dispersion_formula_2(self): src = Source(wavelength=0.5) SiO2 = Material(filename='main/SiO2/Ghosh-e.yml', source=src) n_desired = 1.5580 n_actual = SiO2.n assertAlmostEqual(n_actual, n_desired, absoluteTolerance=1e-5)
# Contact: [email protected] # Creation Date: 11/01/2019 # import context from rcwa import Material, Layer, LayerStack, Source, Solver, Plotter import numpy as np import pandas as pd from matplotlib import pyplot as plt startWavelength = 0.25 stopWavelength = 0.850 stepWavelength = 0.001 incident_angle = np.radians(75) source = Source(wavelength=startWavelength, theta=incident_angle) si = Material('Si') breakpoint() reflectionLayer = Layer(n=1) # Free space transmissionLayer = Layer(material=si) stack = LayerStack(reflectionLayer, transmissionLayer) print("Solving system...") TMMSolver = Solver(stack, source, (1, 1)) wavelengths = np.arange(startWavelength, stopWavelength + stepWavelength, stepWavelength) TMMSolver.Solve(wavelengths=wavelengths) tan_psi_predicted = np.array([result['tanPsi'] for result in TMMSolver.results])
def setUp(self): self.absoluteTolerance = 1e-4 self.relativeTolerance = 1e-3 reflectionLayer = Layer(er=1.4, ur=1.2) transmissionLayer = Layer(er=1.8, ur=1.6) # NOTE: t1 AND t2 MUST BE NORMALIZED BY MULTIPLYING BY k0, OTHERWISE THIS WILL NOT WORK, AS # EVERYTHING WAS FORMULATED IN TERMS OF NORMALIZED WAVEVECTORS. I DON'T KNOW OF AN ELEGANT WAY # TO DO THIS OTHER THAN REQUIRING A CRYSTAL TO HAVE A SOURCE AS THE INPUT. I DON'T KNOW OF # AN EASY WAY TO FIX THIS. I'M GOING TO FUDGE IT FOR NOW. wavelength = 2.7 k0 = 2 * pi / wavelength theta = 57 * deg phi = 23 * deg pTEM = 1 / sqrt(2) * complexArray([1, 1j]) source = Source(wavelength=wavelength, theta=theta, phi=phi, pTEM=pTEM, layer=reflectionLayer) thicknessLayer1 = wavelength * 0.25 # should be 0.5 thicknessLayer2 = wavelength * 0.5 # should be 0.3 numberHarmonics = (1, 1) layer1 = Layer(er=2.0, ur=1.0, L=thicknessLayer1) layer2 = Layer(er=1.0, ur=3.0, L=thicknessLayer2) layerStack = LayerStack(reflectionLayer, layer1, layer2, transmissionLayer) self.solver = Solver(layerStack, source, numberHarmonics) self.Kx = 1.0006 self.Ky = 0.4247 self.KzReflectionRegion = 0.705995 self.kIncident = complexArray( [self.Kx, self.Ky, self.KzReflectionRegion]) self.KzTransmissionRegion = 1.30324 self.KzGapRegion = 1 self.rx = 0.0519 - 0.2856j self.ry = -0.4324 + 0.0780j self.rz = 0.1866 + 0.3580j self.tx = -0.0101 + 0.3577j self.ty = 0.4358 - 0.0820j self.tz = -0.1343 - 0.2480j self.R = 0.4403 self.T = 0.5597 self.tanPsi = 1.0538 self.cosDelta = 0.997733 self.delta = -0.0673421 #self.rTE = -0.418308 + 0.183386j #self.rTM = -0.222488 - 0.426831j self.rTE = -0.591577 + 0.259348j self.rTM = -0.60363 + 0.314646j self.KzGap = 1 self.WGap = complexIdentity(2) self.VGap = complexArray([[0 - 0.4250j, 0 - 1.1804j], [0 + 2.0013j, 0 + 0.4250j]]) self.ALayer1 = complexArray([[2.0049, -0.0427], [-0.0427, 2.0873]]) self.BLayer1 = complexArray([[-0.0049, 0.0427], [0.0427, -0.0873]]) self.XLayer1 = complexArray([[0.1493 + 0.9888j, 0 + 0j], [0 + 0j, 0.1493 + 0.9888j]]) self.DLayer1 = complexArray([[2.0057 - 0.0003j, -0.0445 + 0.0006j], [-0.0445 + 0.0006j, 2.0916 - 0.0013j]]) self.ALayer2 = complexArray([[3.8324, 0.2579], [0.2579, 3.3342]]) self.BLayer2 = complexArray([[-1.8324, -0.2579], [-0.2579, -1.3342]]) self.XLayer2 = complexArray([[-0.4583 - 0.8888j, 0 + 0j], [0 + 0j, -0.4583 - 0.8888j]]) self.DLayer2 = complexArray([[4.3436 - 0.7182j, 0.3604 - 0.1440j], [0.3604 - 0.1440j, 3.6475 - 0.4401j]]) self.S11Layer1 = complexArray([[0.0039 - 0.0006j, -0.0398 + 0.0060j], [-0.0398 + 0.0060j, 0.0808 - 0.0121j]]) self.S11Layer2 = complexArray([[0.6997 - 0.2262j, 0.0517 - 0.0014j], [0.0517 - 0.0014j, 0.5998 - 0.2235j]]) self.S12Layer1 = complexArray([[0.1490 + 0.9880j, 0.0005 + 0.0017j], [0.0005 + 0.0017j, 0.1480 + 0.9848j]]) self.S12Layer2 = complexArray([[-0.2093 - 0.6406j, 0.0311 + 0.0390j], [0.0311 + 0.0390j, -0.2693 - 0.7160j]]) self.S21Layer1 = complexArray([[0.1490 + 0.9880j, 0.0005 + 0.0017j], [0.0005 + 0.0017j, 0.1480 + 0.9848j]]) self.S21Layer2 = complexArray([[-0.2093 - 0.6406j, 0.0311 + 0.0390j], [0.0311 + 0.0390j, -0.2693 - 0.7160j]]) self.S22Layer1 = complexArray([[0.0039 - 0.0006j, -0.0398 + 0.0060j], [-0.0398 + 0.0060j, 0.0808 - 0.0121j]]) self.S22Layer2 = complexArray([[0.6997 - 0.2262j, 0.0517 - 0.0014j], [0.0517 - 0.0014j, 0.5998 - 0.2235j]]) self.SLayer1 = complexArray([[self.S11Layer1, self.S12Layer1], [self.S21Layer1, self.S22Layer1]]) self.SLayer2 = complexArray([[self.S11Layer2, self.S12Layer2], [self.S21Layer2, self.S22Layer2]]) self.transparentSMatrix = complexZeros((2, 2, 2, 2)) self.transparentSMatrix[1, 0] = complexIdentity(2) self.transparentSMatrix[0, 1] = complexIdentity(2) self.SReflectionRegion = complexZeros((2, 2, 2, 2)) self.SReflectionRegion[0, 0] = complexArray([[-0.0800, 0.0761], [0.0761, -0.2269]]) self.SReflectionRegion[0, 1] = complexArray([[1.0800, -0.0761], [-0.0761, 1.2269]]) self.SReflectionRegion[1, 0] = complexArray([[0.9200, 0.0761], [0.0761, 0.7731]]) self.SReflectionRegion[1, 1] = complexArray([[0.0800, -0.0761], [-0.0761, 0.2269]]) self.STransmissionRegion = complexZeros((2, 2, 2, 2)) self.STransmissionRegion[0, 0] = complexArray([[0.2060, 0.0440], [0.0440, 0.1209]]) self.STransmissionRegion[0, 1] = complexArray([[0.7940, -0.0440], [-0.0440, 0.8791]]) self.STransmissionRegion[1, 0] = complexArray([[1.2060, 0.0440], [0.0440, 1.1209]]) self.STransmissionRegion[1, 1] = complexArray([[-0.2060, -0.0440], [-0.0440, -0.1209]])
def testGenerateKxMatrix(self): absoluteTolerance = 1e-4 relativeTolerance = 1e-3 # Test our KX matrix at the gamma point kxMatrixActual = self.KxMatrixGPoint sourceGPoint = Source() sourceGPoint.kIncident = self.incidentKVectorGPoint sourceGPoint.k0 = 1 kxMatrixCalculated = generateKxMatrix(sourceGPoint, self.crystal, self.numberHarmonics) assertAlmostEqual(kxMatrixActual, kxMatrixCalculated, absoluteTolerance, relativeTolerance, "testHarmonics: Kx at Gamma Point") # Test our KX matrix at the X point kxMatrixActual = self.KxMatrixXPoint sourceXPoint = Source() sourceXPoint.kIncident = self.incidentKVectorXPoint sourceXPoint.k0 = 1 kxMatrixCalculated = generateKxMatrix(sourceXPoint, self.crystal, self.numberHarmonics) assertAlmostEqual(kxMatrixActual, kxMatrixCalculated, absoluteTolerance, relativeTolerance, "testHarmonics: Kx at X Point") # Test our KX matrix at the M point kxMatrixActual = self.KxMatrixMPoint sourceMPoint = Source() sourceMPoint.kIncident = self.incidentKVectorMPoint sourceMPoint.k0 = 1 kxMatrixCalculated = generateKxMatrix(sourceMPoint, self.crystal, self.numberHarmonics) assertAlmostEqual(kxMatrixActual, kxMatrixCalculated, absoluteTolerance, relativeTolerance, "testHarmonics: Kx at M Point")
def setUp(self): self.numberHarmonics = (3, 3, 1) self.matrixDimensions = np.prod(self.numberHarmonics) self.matrixShape = (self.matrixDimensions, self.matrixDimensions) a = 1 self.ax = a self.ay = a self.r = 0.35 * a self.er = 9.0 self.Nx = 512 self.Ny = 512 self.dx = self.ax / self.Nx self.dy = self.ay / self.Ny self.t1 = complexArray([self.ax, 0]) self.t2 = complexArray([0, self.ay]) self.T1 = (2 * pi / self.ax) * complexArray([1, 0]) self.T2 = (2 * pi / self.ay) * complexArray([0, 1]) self.incidentKVectorGPoint = 0 * self.T1 self.incidentKVectorXPoint = 0.5 * self.T1 self.incidentKVectorMPoint = 0.5 * self.T1 + 0.5 * self.T2 xcoors = np.linspace(-self.ax / 2 + self.dx / 2, self.ax / 2 - self.dx / 2, self.Nx) ycoors = np.linspace(-self.ay / 2 + self.dy / 2, self.ay / 2 - self.dy / 2, self.Ny) (X, Y) = np.meshgrid(xcoors, ycoors) self.UR = complexOnes((self.Nx, self.Ny)) self.ER = (self.er - 1) * np.heaviside(sq(X) + sq(Y) - sq(self.r), 1) self.ER = self.ER + 1 source = Source() self.crystal = Crystal(self.ER, self.UR, self.t1, self.t2) # The data for Kx, Ky, and Kz will be re-used at each point of key symmetry self.KxMatrixGPoint = complexZeros(self.matrixShape) self.KxMatrixGPoint[0, 0] = 6.2832 self.KxMatrixGPoint[2, 2] = -6.2832 self.KxMatrixGPoint[3, 3] = 6.2832 self.KxMatrixGPoint[5, 5] = -6.2832 self.KxMatrixGPoint[6, 6] = 6.2832 self.KxMatrixGPoint[8, 8] = -6.2832 self.KyMatrixGPoint = complexZeros(self.matrixShape) self.KyMatrixGPoint[0, 0] = 6.2832 self.KyMatrixGPoint[1, 1] = 6.2832 self.KyMatrixGPoint[2, 2] = 6.2832 self.KyMatrixGPoint[6, 6] = -6.2832 self.KyMatrixGPoint[7, 7] = -6.2832 self.KyMatrixGPoint[8, 8] = -6.2832 self.KxMatrixXPoint = complexZeros(self.matrixShape) self.KxMatrixXPoint[0, 0] = 9.4248 self.KxMatrixXPoint[1, 1] = 3.1416 self.KxMatrixXPoint[2, 2] = -3.1416 self.KxMatrixXPoint[3, 3] = 9.4248 self.KxMatrixXPoint[4, 4] = 3.1416 self.KxMatrixXPoint[5, 5] = -3.1416 self.KxMatrixXPoint[6, 6] = 9.4248 self.KxMatrixXPoint[7, 7] = 3.1416 self.KxMatrixXPoint[8, 8] = -3.1416 diagonalValuesKyXPoint = complexArray( [6.2832, 6.2832, 6.2832, 0, 0, 0, -6.2832, -6.2832, -6.2832]) self.KyMatrixXPoint = np.diag(diagonalValuesKyXPoint) diagonalValuesKxMPoint = complexArray([ 9.4248, 3.1416, -3.1416, 9.4248, 3.1416, -3.1416, 9.4248, 3.1416, -3.1416 ]) self.KxMatrixMPoint = np.diag(diagonalValuesKxMPoint) diagonalValuesKyMPoint = complexArray([ 9.4248, 9.4248, 9.4248, 3.1416, 3.1416, 3.1416, -3.1416, -3.1416, -3.1416 ]) self.KyMatrixMPoint = np.diag(diagonalValuesKyMPoint)