def basic_test(): """ Compare with program I wrote previously in Mathematica. Also confirms that I don't accidentally mess up the program by editing. """ n_list = [1, 2 + 4j, 3 + 0.3j, 1 + 0.1j] d_list = [inf, 2, 3, inf] th_0 = 0.1 lam_vac = 100 print('The following should all be zero (within rounding errors):') s_data = coh_tmm('s', n_list, d_list, th_0, lam_vac) print(df(s_data['r'], -0.60331226568845775 - 0.093522181653632019j)) print(df(s_data['t'], 0.44429533471192989 + 0.16921936169383078j)) print(df(s_data['R'], 0.37273208839139516)) print(df(s_data['T'], 0.22604491247079261)) p_data = coh_tmm('p', n_list, d_list, th_0, lam_vac) print(df(p_data['r'], 0.60102654255772481 + 0.094489146845323682j)) print(df(p_data['t'], 0.4461816467503148 + 0.17061408427088917j)) print(df(p_data['R'], 0.37016110373044969)) print(df(p_data['T'], 0.22824374314132009)) ellips_data = ellips(n_list, d_list, th_0, lam_vac) print(df(ellips_data['psi'], 0.78366777347038352)) print(df(ellips_data['Delta'], 0.0021460774404193292)) return
def sample2(): """ Here's the transmitted intensity versus wavelength through a single-layer film which has some complicated wavelength-dependent index of refraction. (I made these numbers up, but in real life they could be read out of a graph / table published in the literature.) Air is on both sides of the film, and the light is normally incident. """ #index of refraction of my material: wavelength in nm versus index. material_nk_data = array([[200, 2.1 + 0.1j], [300, 2.4 + 0.3j], [400, 2.3 + 0.4j], [500, 2.2 + 0.4j], [750, 2.2 + 0.5j]]) material_nk_fn = interp1d(material_nk_data[:, 0].real, material_nk_data[:, 1], kind='quadratic') d_list = [inf, 300, inf] #in nm lambda_list = linspace(200, 750, 400) #in nm T_list = [] for lambda_vac in lambda_list: n_list = [1, material_nk_fn(lambda_vac), 1] T_list.append(coh_tmm('s', n_list, d_list, 0, lambda_vac)['T']) plt.figure() plt.plot(lambda_list, T_list) plt.xlabel('Wavelength (nm)') plt.ylabel('Fraction of power transmitted') plt.title('Transmission at normal incidence') plt.show()
def sample6(): """ An example reflection plot with a surface plasmon resonance (SPR) dip. Compare with http://doi.org/10.2320/matertrans.M2010003 ("Spectral and Angular Responses of Surface Plasmon Resonance Based on the Kretschmann Prism Configuration") Fig 6a """ # list of layer thicknesses in nm d_list = [inf, 5, 30, inf] # list of refractive indices n_list = [1.517, 3.719 + 4.362j, 0.130 + 3.162j, 1] # wavelength in nm lam_vac = 633 # list of angles to plot theta_list = linspace(30 * degree, 60 * degree, num=300) # initialize lists of y-values to plot Rp = [] for theta in theta_list: Rp.append(coh_tmm('p', n_list, d_list, theta, lam_vac)['R']) plt.figure() plt.plot(theta_list / degree, Rp, 'blue') plt.xlabel('theta (degree)') plt.ylabel('Fraction reflected') plt.xlim(30, 60) plt.ylim(0, 1) plt.title( 'Reflection of p-polarized light with Surface Plasmon Resonance\n' 'Compare with http://doi.org/10.2320/matertrans.M2010003 Fig 6a') plt.show()
def sample1(): """ Here's a thin non-absorbing layer, on top of a thick absorbing layer, with air on both sides. Plotting reflected intensity versus wavenumber, at two different incident angles. """ # list of wavenumbers to plot in nm^-1 ks=linspace(0.0025,.00125,num=800) # list of layer thicknesses in nm ks=linspace(0.0025,.00125,num=800) d0 = inf d1 = 92 d2 = 91 d3 = inf d_list = [d0, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d1, d3] material_nk_data2 = array([[0.0025, 1.575+0.17j], # @400nm [0.002, 1.5552+0.15j], # @500nm [0.001667, 1.5444+0.14j], # @600nm [0.001429, 1.53796+0.13j], # @700nm [0.00125, 1.53375+0.12j]]) # @800nm material_nk_fn2 = interp1d(material_nk_data2[:,0].real, material_nk_data2[:,1], kind='quadratic') material_nk_data1 = array([[0.0025, 1.705+0.06j], # @400nm [0.002, 1.6852+0.04j], # @500nm [0.001667, 1.6744+0.03j], # @600nm [0.001429, 1.66796+0.02j], # @700nm [0.00125, 1.66375+0.014j]]) # @800nm material_nk_fn1 = interp1d(material_nk_data1[:,0].real, material_nk_data1[:,1], kind='quadratic') # initialize lists of y-values to plot Rnorm=[] R37=[] for k in ks: # For normal incidence, s and p polarizations are identical. # I arbitrarily decided to use 's'. n_list = [1, material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), 1.615+0.085j] Rnorm.append(coh_tmm('s',n_list, d_list, 0, 1/k)['R']) #R37.append(unpolarized_RT(n_list, d_list, 37*degree, 1/k)['R']) kcm = ks * 1e7 #ks in cm^-1 rather than nm^-1 lamb = 1/ks plt.figure() plt.plot(lamb,Rnorm,'blue',expx,expy,'purple') plt.xlabel('Wavelength (/nm)') plt.ylabel('Fraction reflected') plt.title('Simulated reflection of unpolarized light at 0$^\circ$ incidence (blue), ' 'Experimental data (purple)') plt.axis([400, 800, 0, 0.25])
def sample1(): """ Here's a thin non-absorbing layer, on top of a thick absorbing layer, with air on both sides. Plotting reflected intensity versus wavenumber, at two different incident angles. """ # list of layer thicknesses in nm d_list = [inf, 100, 300, inf] # list of refractive indices n_list = [1, 2.2, 3.3 + 0.3j, 1] # list of wavenumbers to plot in nm^-1 ks = linspace(0.0001, .01, num=400) # initialize lists of y-values to plot Rnorm = [] R45 = [] for k in ks: # For normal incidence, s and p polarizations are identical. # I arbitrarily decided to use 's'. Rnorm.append(coh_tmm('s', n_list, d_list, 0, 1 / k)['R']) R45.append(unpolarized_RT(n_list, d_list, 45 * degree, 1 / k)['R']) kcm = ks * 1e7 #ks in cm^-1 rather than nm^-1 plt.figure() plt.plot(kcm, Rnorm, 'blue', kcm, R45, 'purple') plt.xlabel('k (cm$^{-1}$)') plt.ylabel('Fraction reflected') plt.title('Reflection of unpolarized light at 0$^\circ$ incidence (blue), ' '45$^\circ$ (purple)') plt.show()
def sample4(): """ Here is an example where we plot absorption and Poynting vector as a function of depth. """ d_list = [inf, 100, 300, inf] #in nm n_list = [1, 2.2 + 0.2j, 3.3 + 0.3j, 1] th_0 = pi / 4 lam_vac = 400 pol = 'p' coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) ds = linspace(-50, 400, num=1000) #position in structure poyn = [] absor = [] for d in ds: layer, d_in_layer = find_in_structure_with_inf(d_list, d) data = position_resolved(layer, d_in_layer, coh_tmm_data) poyn.append(data['poyn']) absor.append(data['absor']) # convert data to numpy arrays for easy scaling in the plot poyn = array(poyn) absor = array(absor) plt.figure() plt.plot(ds, poyn, 'blue', ds, 200 * absor, 'purple') plt.xlabel('depth (nm)') plt.ylabel('AU') plt.title('Local absorption (purple), Poynting vector (blue)') plt.show()
def sample1(): """ Here's a thin non-absorbing layer, on top of a thick absorbing layer, with air on both sides. Plotting reflected intensity versus wavenumber, at two different incident angles. """ # list of wavenumbers to plot in nm^-1 ks=linspace(0.0025,.00125,num=800) # list of layer thicknesses in nm d0 = inf d1 = 117 d2 = 73 d3 = inf d_list = [inf, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d3] # list of refractive indices #Light-constasted layers material_nk_data1 = array([[0.0025, 1.6335+0.0564j], # @400nm [0.002,1.61376+0.0366], # @500nm [0.001667, 1.603+0.025844j], # @600nm [0.001429,1.5965+0.01935j], # @700nm [0.00125, 1.59231+0.001515j]]) # @800nm material_nk_fn1 = interp1d(material_nk_data1[:,0].real, material_nk_data1[:,1], kind='quadratic') #Dark-contrasted layers material_nk_data2 = array([[0.0025,1.5326+0.13955j], # @400nm [0.002, 1.5128+0.11975j], # @500nm [0.001667,1.5024+0.109j], # @600nm [0.001429,1.4956+0.1025j], # @700nm [0.00125,1.49135+0.0983j]]) # @800nm material_nk_fn2 = interp1d(material_nk_data2[:,0].real, material_nk_data2[:,1], kind='quadratic') # initialize lists of y-values to plot Rnorm=[] R37=[] for k in ks: # For normal incidence, s and p polarizations are identical. # I arbitrarily decided to use 's'. n_list = [1, material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k),1.55+0.1j] Rnorm.append(coh_tmm('s',n_list, d_list, 0, 1/k)['R']) #R37.append(unpolarized_RT(n_list, d_list, 37*degree, 1/k)['R']) kcm = ks * 1e7 #ks in cm^-1 rather than nm^-1 lamb = 1/ks plt.figure() plt.plot(lamb,Rnorm,'blue',expx,expy,'purple') plt.xlabel('Wavelength (/nm)') plt.ylabel('Fraction reflected') plt.title('Simulated reflection of unpolarized light at 0$^\circ$ incidence (blue), ' 'Experimental data (purple)') plt.axis([400, 800, 0, 0.25])
def coh_overflow_test(): """ Test whether very very opaque layers will break the coherent program """ n_list = [1., 2 + .1j, 1 + 3j, 4., 5.] d_list = [inf, 50, 1e5, 50, inf] lam = 200 alpha_d = imag(n_list[2]) * 4 * pi * d_list[2] / lam print('Very opaque layer: Calculation should involve e^(-', alpha_d, ')!') data = coh_tmm('s', n_list, d_list, 0, lam) n_list2 = n_list[0:3] d_list2 = d_list[0:3] d_list2[-1] = inf data2 = coh_tmm('s', n_list2, d_list2, 0, lam) print('First entries of the following two lists should agree:') print(data['vw_list']) print(data2['vw_list'])
def calc_reflectances(n_fn_list, d_list, th_0, pol='s', spectral_range='narrow'): """ Calculate the reflection spectrum of a thin-film stack. n_fn_list[m] should be a function that inputs wavelength in nm and outputs refractive index of the m'th layer. In other words, n_fn_list[2](456) == 1.53 + 0.4j mans that layer #2 has a refractive index of 1.53 + 0.4j at 456nm. These functions could be defined with scipy.interpolate.interp1d() for example. pol, d_list and th_0 are defined as in tmm.coh_tmm ... but d_list MUST be in units of nanometers spectral_range can be 'full' if all the functions in n_fn_list can take wavelength arguments between 360-830nm; or 'narrow' if some or all require arguments only in the range 400-700nm. The wavelengths outside the 'narrow' range make only a tiny difference to the color, because they are almost invisible to the eye. If spectral_range is 'narrow', then the n(400) values are used for 360-400 and n(700) for 700-830nm Returns a 2-column array where the first column is wavelength in nm (360,361,362,...,830) and the second column is reflectivity (from 0 to 1, where 1 is a perfect mirror). This range is chosen to be consistent with colorpy.illuminants. See colorpy.ciexyz.start_wl_nm etc. """ lam_vac_list = arange(360, 831) num_layers = len(n_fn_list) def extend_spectral_range(n_fn): """ Starting with a narrow-spectrum refractive index function n_fn(wavelength), create then return the corresponding full-spectrum refractive index function """ def extended_n_fn(lam): if lam < 400: return n_fn(400) elif lam > 700: return n_fn(700) else: return n_fn(lam) return extended_n_fn if spectral_range == 'narrow': n_fn_list = [extend_spectral_range(n_fn) for n_fn in n_fn_list] final_answer = [] for lam_vac in lam_vac_list: n_list = [n_fn_list[i](lam_vac) for i in range(num_layers)] R = coh_tmm(pol, n_list, d_list, th_0, lam_vac)['R'] final_answer.append([lam_vac,R]) final_answer = array(final_answer) return final_answer
def sample1(): """ Here's a thin non-absorbing layer, on top of a thick absorbing layer, with air on both sides. Plotting reflected intensity versus wavenumber, at two different incident angles. """ # list of wavenumbers to plot in nm^-1 ks=linspace(0.0025,.00125,num=800) d0 = inf d1 = 92 d2 = 90 d3 = inf d_list = [d0, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d1, d3] material_nk_data2 = array([[0.0025, 1.575+0.17j], # @400nm [0.002, 1.5552+0.15j], # @500nm [0.001667, 1.5444+0.14j], # @600nm [0.001429, 1.53796+0.13j], # @700nm [0.00125, 1.53375+0.12j]]) # @800nm material_nk_fn2 = interp1d(material_nk_data2[:,0].real, material_nk_data2[:,1], kind='quadratic') material_nk_data1 = array([[0.0025, 1.705+0.06j], # @400nm [0.002, 1.6852+0.04j], # @500nm [0.001667, 1.6744+0.03j], # @600nm [0.001429, 1.66796+0.02j], # @700nm [0.00125, 1.66375+0.014j]]) # @800nm material_nk_fn1 = interp1d(material_nk_data1[:,0].real, material_nk_data1[:,1], kind='quadratic') # initialize lists of y-values to plot Rnorm=[] R37=[] for k in ks: # For normal incidence, s and p polarizations are identical. # I arbitrarily decided to use 's'. n_list = [1, material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), 1.615+0.085j] Rnorm.append(coh_tmm('s',n_list, d_list, 0, 1/k)['R']) #R37.append(unpolarized_RT(n_list, d_list, 37*degree, 1/k)['R']) kcm = ks * 1e7 #ks in cm^-1 rather than nm^-1 lamb = 1/ks plt.figure() plt.plot(lamb,Rnorm,'blue',expx,expy,'purple') plt.xlabel('Wavelength (/nm)') plt.ylabel('Fraction reflected') plt.title('Simulated reflection of unpolarized light at 0$^\circ$ incidence (blue), ' 'Experimental data (purple)') plt.axis([400, 800, 0, 0.25])
def run(self, thicknesses, theta0, polarization=None): """ runs the model with specified parameters :param thicknesses: list of thicknesses, first and last must be inf :param theta0: input angle :param polarization: polarization state 's', 'p', or None :return: void """ self.index_array = np.array(self.mat_df[self.layers]) if polarization is None: self.data = tmm.unpolarized_RT(self.index_array, thicknesses, theta0, self.wavelength) elif polarization in ['p', 's']: self.data = tmm.coh_tmm(polarization, self.index_array, thicknesses, theta0, self.wavelength)
def sample1(): """ Here's a thin non-absorbing layer, on top of a thick absorbing layer, with air on both sides. Plotting reflected intensity versus wavenumber, at two different incident angles. """ # list of layer thicknesses in nm d_list = [inf, 100, 80, 100, 80, 100, 80, 100, 80, 100, 80, 100, 80, inf] # list of refractive indices n_list = [ 1, 1.68 + 0.03j, 1.55 + 0.14j, 1.68 + 0.03j, 1.55 + 0.14j, 1.68 + 0.03j, 1.55 + 0.14j, 1.68 + 0.03j, 1.55 + 0.14j, 1.68 + 0.03j, 1.55 + 0.14j, 1.68 + 0.03j, 1.55 + 0.14j, 1.61 + 0.085j ] # list of wavenumbers to plot in nm^-1 ks = linspace(0.0025, .00125, num=800) # initialize lists of y-values to plot Rnorm = [] R37 = [] for k in ks: # For normal incidence, s and p polarizations are identical. # I arbitrarily decided to use 's'. Rnorm.append(coh_tmm('s', n_list, d_list, 0, 1 / k)['R']) R37.append(unpolarized_RT(n_list, d_list, 37 * degree, 1 / k)['R']) kcm = ks * 1e7 #ks in cm^-1 rather than nm^-1 lamb = 1 / ks plt.figure() plt.plot(lamb, Rnorm, 'blue', lamb, R37, 'purple') plt.xlabel('Wavelength (/nm)') plt.ylabel('Fraction reflected') plt.title('Reflection of unpolarized light at 0$^\circ$ incidence (blue), ' '37$^\circ$ (purple)') # data file import numpy datafile_path = "/users/Olimpia/Desktop/datafile.txt" datafile_id = open(datafile_path, 'w+') data = numpy.array([lamb, Rnorm]) data = data.T numpy.savetxt(datafile_id, data, fmt=['%.4f', '%.4f']) datafile_id.close()
def absorp_analytic_fn_test(): """ Test absorp_analytic_fn functions """ d_list = [inf, 100, 300, inf] #in nm n_list = [1, 2.2 + 0.2j, 3.3 + 0.3j, 1] th_0 = pi / 4 lam_vac = 400 layer = 1 d = d_list[layer] dist = 37 print('The following should all be zero (within rounding errors):') for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) expected_absorp = position_resolved(layer, dist, coh_tmm_data)['absor'] absorp_fn = absorp_analytic_fn() absorp_fn.fill_in(coh_tmm_data, layer) print(df(absorp_fn.run(dist), expected_absorp)) absorp_fn2 = absorp_fn.copy().flip() dist_from_other_side = d - dist print(df(absorp_fn2.run(dist_from_other_side), expected_absorp)) return
def position_resolved_test(): """ Compare with program I wrote previously in Mathematica. Also, various consistency checks. """ d_list = [inf, 100, 300, inf] #in nm n_list = [1, 2.2 + 0.2j, 3.3 + 0.3j, 1] th_0 = pi / 4 lam_vac = 400 layer = 1 dist = 37 print('The following should all be zero (within rounding errors):') pol = 'p' coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) print( df(coh_tmm_data['kz_list'][1], 0.0327410685922732 + 0.003315885921866465j)) data = position_resolved(layer, dist, coh_tmm_data) print(df(data['poyn'], 0.7094950598055798)) print(df(data['absor'], 0.005135049118053356)) print(df(1, sum(absorp_in_each_layer(coh_tmm_data)))) pol = 's' coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) print( df(coh_tmm_data['kz_list'][1], 0.0327410685922732 + 0.003315885921866465j)) data = position_resolved(layer, dist, coh_tmm_data) print(df(data['poyn'], 0.5422594735025152)) print(df(data['absor'], 0.004041912286816303)) print(df(1, sum(absorp_in_each_layer(coh_tmm_data)))) #Poynting vector derivative should equal absorption for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data1 = position_resolved(layer, dist, coh_tmm_data) data2 = position_resolved(layer, dist + 0.001, coh_tmm_data) print( 'Finite difference should approximate derivative. Difference is ' + str( df((data1['absor'] + data2['absor']) / 2, (data1['poyn'] - data2['poyn']) / 0.001))) #Poynting vector at end should equal T layer = 2 dist = 300 for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) print(df(data['poyn'], coh_tmm_data['T'])) #Poynting vector at start should equal power_entering layer = 1 dist = 0 for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) print(df(data['poyn'], coh_tmm_data['power_entering'])) #Poynting vector should be continuous for pol in ['s', 'p']: layer = 1 dist = 100 coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) poyn1 = data['poyn'] layer = 2 dist = 0 coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) poyn2 = data['poyn'] print(df(poyn1, poyn2)) return
def sample1(): """ Here's a thin non-absorbing layer, on top of a thick absorbing layer, with air on both sides. Plotting reflected intensity versus wavenumber, at two different incident angles. """ # list of wavenumbers to plot in nm^-1 ks = linspace(0.0025, .00125, num=800) # list of layer thicknesses in nm d0 = inf d1 = 117 d2 = 73 d3 = inf d_list = [inf, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d1, d2, d3] # list of refractive indices #Light-constasted layers material_nk_data1 = array([ [0.0025, 1.6335 + 0.0564j], # @400nm [0.002, 1.61376 + 0.0366], # @500nm [0.001667, 1.603 + 0.025844j], # @600nm [0.001429, 1.5965 + 0.01935j], # @700nm [0.00125, 1.59231 + 0.001515j] ]) # @800nm material_nk_fn1 = interp1d(material_nk_data1[:, 0].real, material_nk_data1[:, 1], kind='quadratic') #Dark-contrasted layers material_nk_data2 = array([ [0.0025, 1.5326 + 0.13955j], # @400nm [0.002, 1.5128 + 0.11975j], # @500nm [0.001667, 1.5024 + 0.109j], # @600nm [0.001429, 1.4956 + 0.1025j], # @700nm [0.00125, 1.49135 + 0.0983j] ]) # @800nm material_nk_fn2 = interp1d(material_nk_data2[:, 0].real, material_nk_data2[:, 1], kind='quadratic') # initialize lists of y-values to plot Rnorm = [] R37 = [] for k in ks: # For normal incidence, s and p polarizations are identical. # I arbitrarily decided to use 's'. n_list = [ 1, material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), material_nk_fn1(k), material_nk_fn2(k), 1.55 + 0.1j ] Rnorm.append(coh_tmm('s', n_list, d_list, 0, 1 / k)['R']) #R37.append(unpolarized_RT(n_list, d_list, 37*degree, 1/k)['R']) kcm = ks * 1e7 #ks in cm^-1 rather than nm^-1 lamb = 1 / ks plt.figure() plt.plot(lamb, Rnorm, 'blue', expx, expy, 'purple') plt.xlabel('Wavelength (/nm)') plt.ylabel('Fraction reflected') plt.title( 'Simulated reflection of unpolarized light at 0$^\circ$ incidence (blue), ' 'Experimental data (purple)') plt.axis([400, 800, 0, 0.25])
def incoherent_test(): """ test inc_tmm(). To do: Add more tests. """ print('The following should all be zero (within rounding errors):') #3-incoherent-layer test, real refractive indices (so that R and T are the #same in both directions) n0 = 1 n1 = 2 n2 = 3 n_list = [n0, n1, n2] d_list = [inf, 567, inf] c_list = ['i', 'i', 'i'] th0 = pi / 3 th1 = snell(n0, n1, th0) th2 = snell(n0, n2, th0) lam_vac = 400 for pol in ['s', 'p']: inc_data = inc_tmm(pol, n_list, d_list, c_list, th0, lam_vac) R0 = abs(interface_r(pol, n0, n1, th0, th1)**2) R1 = abs(interface_r(pol, n1, n2, th1, th2)**2) T0 = 1 - R0 RR = R0 + R1 * T0**2 / (1 - R0 * R1) print(df(inc_data['R'], RR)) print(df(inc_data['R'] + inc_data['T'], 1)) #One finite layer with incoherent layers on both sides. Should agree with #coherent program n0 = 1 + 0.1j n1 = 2 + 0.2j n2 = 3 + 0.4j n_list = [n0, n1, n2] d_list = [inf, 100, inf] c_list = ['i', 'c', 'i'] n00 = 1 th00 = pi / 3 th0 = snell(n00, n0, th00) lam_vac = 400 for pol in ['s', 'p']: inc_data = inc_tmm(pol, n_list, d_list, c_list, th0, lam_vac) coh_data = coh_tmm(pol, n_list, d_list, th0, lam_vac) print(df(inc_data['R'], coh_data['R'])) print(df(inc_data['T'], coh_data['T'])) print(df(1, sum(inc_absorp_in_each_layer(inc_data)))) #One finite layer with three incoherent layers. Should agree with #manual calculation + coherent program n0 = 1 + 0.1j n1 = 2 + 0.2j n2 = 3 + 0.004j n3 = 4 + 0.2j d1 = 100 d2 = 10000 n_list = [n0, n1, n2, n3] d_list = [inf, d1, d2, inf] c_list = ['i', 'c', 'i', 'i'] n00 = 1 th00 = pi / 3 th0 = snell(n00, n0, th00) lam_vac = 400 for pol in ['s', 'p']: inc_data = inc_tmm(pol, n_list, d_list, c_list, th0, lam_vac) coh_data = coh_tmm(pol, [n0, n1, n2], [inf, d1, inf], th0, lam_vac) th2 = snell(n0, n2, th0) th3 = snell(n0, n3, th0) coh_bdata = coh_tmm(pol, [n2, n1, n0], [inf, d1, inf], th2, lam_vac) R02 = coh_data['R'] R20 = coh_bdata['R'] T02 = coh_data['T'] T20 = coh_bdata['T'] P2 = exp(-4 * pi * d2 * (n2 * cos(th2)).imag / lam_vac) #fraction passing through R23 = interface_R(pol, n2, n3, th2, th3) T23 = interface_T(pol, n2, n3, th2, th3) #T = T02 * P2 * T23 + T02 * P2 * R23 * P2 * R20 * P2 * T23 + ... T = T02 * P2 * T23 / (1 - R23 * P2 * R20 * P2) #R = R02 # + T02 * P2 * R23 * P2 * T20 # + T02 * P2 * R23 * P2 * R20 * P2 * R23 * P2 * T20 + ... R = R02 + T02 * P2 * R23 * P2 * T20 / (1 - R20 * P2 * R23 * P2) print(df(inc_data['T'], T)) print(df(inc_data['R'], R)) #The coherent program with a thick but randomly-varying-thickness substrate #should agree with the incoherent program. nair = 1 + 0.1j nfilm = 2 + 0.2j nsub = 3 nf = 3 + 0.4j n_list = [nair, nfilm, nsub, nf] n00 = 1 th00 = pi / 3 th0 = snell(n00, n0, th00) lam_vac = 400 for pol in ['s', 'p']: d_list_inc = [inf, 100, 1, inf] #sub thickness doesn't matter here c_list = ['i', 'c', 'i', 'i'] inc_data = inc_tmm(pol, n_list, d_list_inc, c_list, th0, lam_vac) coh_Rs = [] coh_Ts = [] for dsub in np.linspace(10000, 30000, 357): d_list = [inf, 100, dsub, inf] coh_data = coh_tmm(pol, n_list, d_list, th0, lam_vac) coh_Rs.append(coh_data['R']) coh_Ts.append(coh_data['T']) print('Coherent with random thickness should agree with incoherent. ' + 'Discrepency is: ' + str(df(average(coh_Rs), inc_data['R']))) print('Coherent with random thickness should agree with incoherent. ' + 'Discrepency is: ' + str(df(average(coh_Ts), inc_data['T']))) #The coherent program with a thick substrate and randomly-varying wavelength #should agree with the incoherent program. n0 = 1 + 0.0j n_list = [n0, 2 + 0.0002j, 3 + 0.0001j, 3 + 0.4j] n00 = 1 th00 = pi / 3 th0 = snell(n00, n0, th00) d_list = [inf, 10000, 10200, inf] c_list = ['i', 'i', 'i', 'i'] for pol in ['s', 'p']: inc_absorp = array([0., 0., 0., 0.]) coh_absorp = array([0., 0., 0., 0.]) num_pts = 234 for lam_vac in np.linspace(40, 50, num_pts): inc_data = inc_tmm(pol, n_list, d_list, c_list, th0, lam_vac) inc_absorp += array(inc_absorp_in_each_layer(inc_data)) coh_data = coh_tmm(pol, n_list, d_list, th0, lam_vac) coh_absorp += array(absorp_in_each_layer(coh_data)) inc_absorp /= num_pts coh_absorp /= num_pts print( 'Coherent with random wavelength should agree with incoherent. ' + 'The two rows of this array should be the same:') print(vstack((inc_absorp, coh_absorp)))
def position_resolved_test2(): """ Similar to position_resolved_test(), but with initial and final medium having a complex refractive index. """ d_list = [inf, 100, 300, inf] #in nm # "00" is before the 0'th layer. This is easy way to generate th0, ensuring #that n0*sin(th0) is real. n00 = 1 th00 = pi / 4 n0 = 1 + 0.1j th_0 = snell(n00, n0, th00) n_list = [n0, 2.2 + 0.2j, 3.3 + 0.3j, 1 + 0.4j] lam_vac = 400 layer = 1 dist = 37 print('The following should all be zero (within rounding errors):') for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) print(df(1, sum(absorp_in_each_layer(coh_tmm_data)))) #Poynting vector derivative should equal absorption for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data1 = position_resolved(layer, dist, coh_tmm_data) data2 = position_resolved(layer, dist + 0.001, coh_tmm_data) print( 'Finite difference should approximate derivative. Difference is ' + str( df((data1['absor'] + data2['absor']) / 2, (data1['poyn'] - data2['poyn']) / 0.001))) #Poynting vector at end should equal T layer = 2 dist = 300 for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) print(df(data['poyn'], coh_tmm_data['T'])) #Poynting vector at start should equal power_entering layer = 1 dist = 0 for pol in ['s', 'p']: coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) print(df(data['poyn'], coh_tmm_data['power_entering'])) #Poynting vector should be continuous for pol in ['s', 'p']: layer = 1 dist = 100 coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) poyn1 = data['poyn'] layer = 2 dist = 0 coh_tmm_data = coh_tmm(pol, n_list, d_list, th_0, lam_vac) data = position_resolved(layer, dist, coh_tmm_data) poyn2 = data['poyn'] print(df(poyn1, poyn2)) return