makeqx.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. import snlay as sn
  2. import numpy as np
  3. from scipy import interpolate
  4. from noise import pnoise1
  5. import random
  6. from tmm import coh_tmm
  7. import multiprocessing as mp
  8. #import pyximport; pyximport.install(pyimport=True)
  9. #import mtmm as mtmm
  10. #make a materials dictionary
  11. matsdict = {
  12. 1: './materials/gold.dat',
  13. 2: './materials/silicon.dat',
  14. 3: './materials/silica.dat',
  15. 4: './materials/tio2.dat',
  16. 5: './materials/silver.dat'
  17. }
  18. def get_nk(datafile, wavelengths):
  19. """Reads the given file and returns the n+ik complex at
  20. the given wavelength after suitable interpolation
  21. :datafile: TODO
  22. :wavelength: TODO
  23. :returns: TODO
  24. """
  25. rawdisp = np.loadtxt(datafile)
  26. f_r = interpolate.interp1d(rawdisp[:,0], rawdisp[:,1])
  27. f_i = interpolate.interp1d(rawdisp[:,0], rawdisp[:,2])
  28. return f_r(wavelengths) + 1j*f_i(wavelengths)
  29. def nk_2_eps(n):
  30. """TODO: Docstring for nk_2_epsnk_2_eps.
  31. :returns: complex epsilon given n and kappa
  32. """
  33. eps_r = n.real**2 - n.imag**2
  34. eps_i = 2*n.real*n.imag
  35. return eps_r + 1j*eps_i
  36. def eps_2_nk(eps):
  37. """TODO: Docstring for nk_2_epsnk_2_eps.
  38. :returns: complex epsilon given n and kappa
  39. """
  40. modeps = np.abs(eps)
  41. n_r = np.sqrt(0.5*(modeps + eps.real))
  42. n_i = np.sqrt(0.5*(modeps - eps.real))
  43. return n_r + 1j*n_i
  44. def LL_mixing(fH, n_H, n_L):
  45. """TODO: Docstring for brugg_mixingbrugg_mixing.
  46. Given the volumne fraction of the higher index material, give the effective
  47. index of the layer
  48. :fH: volumne fraction from 0 to 1
  49. :n_H: ri of the higher index material
  50. :n_L: ri of the lower index material
  51. :returns: TODO
  52. """
  53. eH = nk_2_eps(n_H)
  54. eL = nk_2_eps(n_L)
  55. bigK = fH*(eH - 1)/(eH + 2) + (1 - fH)*(eL - 1)/(eL + 2)
  56. e_eff = (1 + 2*bigK)/(1 - bigK)
  57. return eps_2_nk(e_eff)
  58. def bet01(x):
  59. x = x - np.amin(x)
  60. x = x/np.amax(x)
  61. return x
  62. def make_qx(num_layers):
  63. """generate a random q_x array
  64. :num_layers: the number of layers
  65. :returns: a random function with bounds 0 and 1
  66. """
  67. uni = np.linspace(0, num_layers, num_layers, endpoint=False)
  68. rwalk = np.ones_like(uni)
  69. rwalk[0] = 0
  70. p_motion = random.random()
  71. pos_counter = 0
  72. #Start the random walk.
  73. for i in range(1,num_layers):
  74. test = random.random()
  75. if test >= p_motion:
  76. pos_counter += np.random.uniform(1,10)
  77. else:
  78. pos_counter -= np.random.uniform(1,10)
  79. rwalk[i] = pos_counter
  80. rwalk = bet01(rwalk)
  81. # some random number seeds
  82. samps = int(np.random.uniform(int(num_layers/10)+2, int(9*num_layers/10), 1))
  83. scales = np.random.uniform(0.05, 0.75, 1)
  84. s = np.linspace(-1, num_layers + 1, samps)
  85. fr = np.clip(np.random.normal(loc=0.5, scale=scales, size=samps), 0, 1)
  86. fr_p = s - s
  87. for ctr, x in enumerate(s):
  88. octa = np.random.uniform(1, 8, 1)
  89. pers = np.random.uniform(0.5, 2.2, 1)
  90. fr_p[ctr] = np.clip((0.5 + pnoise1(x, octaves=octa, persistence=pers)), 0, 1)
  91. if np.random.randint(2):
  92. f = interpolate.interp1d(s, fr, kind="quadratic", assume_sorted=True)
  93. else:
  94. f = interpolate.interp1d(s, fr_p, kind="quadratic", assume_sorted=True)
  95. if random.random() >= 0.20:
  96. rwalk = np.clip(f(uni), 0, 1)
  97. return rwalk
  98. def tmm_eval2(
  99. qx,
  100. cthick,
  101. lam_low=400, #in nm
  102. lam_high=1200,
  103. lam_pts=100,
  104. ang_low=0, #degrees
  105. ang_high=90,
  106. ang_pts=25,
  107. n_subs=1.52,
  108. ):
  109. """TODO: Docstring for tmm_eval.
  110. :qx: TODO
  111. :lam_low: TODO
  112. :#in nm
  113. lam_high: TODO
  114. :lam_pts: TODO
  115. :ang_low: TODO
  116. :#degrees
  117. ang_high: TODO
  118. :ang_pts: TODO
  119. :returns: TODO
  120. """
  121. degree = np.pi/180
  122. lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  123. thetas = np.linspace(ang_high, ang_low, endpoint=True, num=ang_pts)
  124. Rs = np.zeros((thetas.size, lams.size))
  125. Rp = np.zeros((thetas.size, lams.size))
  126. for tidx, theta in enumerate(thetas):
  127. for lidx, lam in enumerate(lams):
  128. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  129. Rs[tidx, lidx] = 100*coh_tmm('s',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  130. Rp[tidx, lidx] = 100*coh_tmm('p',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  131. return Rs, Rp
  132. def tmm_eval(
  133. qx,
  134. cthick,
  135. lam_low=400, #in nm
  136. lam_high=1200,
  137. lam_pts=100,
  138. ang_low=0, #degrees
  139. ang_high=90,
  140. ang_pts=25,
  141. n_subs=1.52,
  142. ):
  143. """TODO: Docstring for tmm_eval.
  144. :qx: TODO
  145. :lam_low: TODO
  146. :#in nm
  147. lam_high: TODO
  148. :lam_pts: TODO
  149. :ang_low: TODO
  150. :#degrees
  151. ang_high: TODO
  152. :ang_pts: TODO
  153. :returns: TODO
  154. """
  155. degree = np.pi/180
  156. lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  157. thetas = np.linspace(ang_high, ang_low, endpoint=True, num=ang_pts)
  158. Rs = np.zeros((thetas.size, lams.size))
  159. Rp = np.zeros((thetas.size, lams.size))
  160. for tidx, theta in enumerate(thetas):
  161. for lidx, lam in enumerate(lams):
  162. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  163. Rs[tidx, lidx] = 100*coh_tmm('s',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  164. Rp[tidx, lidx] = 100*coh_tmm('p',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  165. return Rs, Rp
  166. def tmm_eval_wbk(
  167. qx,
  168. cthick,
  169. inc_ang,
  170. lam,
  171. n_subs=1.52
  172. ):
  173. """TODO: Docstring for tmm_eval.
  174. :qx: TODO
  175. :returns: TODO
  176. """
  177. degree = np.pi/180
  178. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  179. Rs = 100*mtmm.coh_tmm('s',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  180. # Rp = 100*coh_tmm('p',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  181. return Rs
  182. def digitize_qx(q_x, dlevels=2):
  183. """TODO: Docstring for digitize_qx.
  184. :q_x: TODO
  185. :returns: TODO
  186. """
  187. #bins = np.array([-0.02, 0.2, 0.4, 0.6, 0.8, 1.01])
  188. bins = np.linspace(0,1, num=dlevels+1, endpoint=True)
  189. bins[0] = -0.02
  190. bins[-1] = 1.01
  191. dig = (np.digitize(q_x, bins, right=True)) - 1
  192. act_r = np.linspace(0, 1, num=dlevels, endpoint=True)
  193. return act_r[dig]
  194. def make_nxdx(qx, n_substrate=1.52):
  195. """TODO: Docstring for make_nxdx.
  196. :qx: TODO
  197. :n_substrate: TODO
  198. :layer_thickness: TODO
  199. :returns: TODO
  200. """
  201. #num_layers = int(qx.size/2)
  202. d_x = [np.inf] + (qx/np.sum(qx)).tolist() + [np.inf]
  203. #qtmp = qx[:,0]
  204. #qtmp = digitize_qx(qx[:,1], dlevels=2)
  205. #d_x = num_layers*[cthick/num_layers]
  206. #d_x = [np.inf] + d_x + [np.inf]
  207. qtmp = np.zeros_like(qx)
  208. qtmp[::2] = qtmp[::2] + 1.0
  209. sde = 1.45 + (2.58 - 1.45)*qtmp
  210. # sde = LL_mixing(fH = qtmp,
  211. # n_H = 2.58, #get_nk(datafile=matsdict[3], wavelengths=wavelen),
  212. # n_L = 1.45) #get_nk(datafile=matsdict[4], wavelengths=wavelen
  213. # # ))
  214. n_x = [1.0] + sde.tolist() + [n_substrate]
  215. return d_x, n_x
  216. def vgdr_eval_wsweep(
  217. qx,
  218. inc_ang,
  219. lam_low=0.25, #in nm
  220. lam_high=1,
  221. lam_pts=256,
  222. n_subs=1.52,
  223. ):
  224. """TODO: Docstring for tmm_eval.
  225. """
  226. degree = np.pi/180
  227. #lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  228. lam_inv = np.linspace(1/lam_low, 1/lam_high, num=lam_pts, endpoint=True)
  229. lams = 1.0/lam_inv
  230. Rs = np.zeros(lams.size)
  231. #Rp = np.zeros(lams.size)
  232. for lidx, lam in enumerate(lams):
  233. d_x, n_x = make_nxdx(qx=qx, n_substrate=n_subs)
  234. Rs[lidx] = 100*coh_tmm('s',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  235. #Rp[lidx] = 100*coh_tmm('p',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  236. #return Rs
  237. vgdr = 100*np.ones(lam_pts)
  238. for idx, lam in enumerate(lams):
  239. if lams[idx] <= lam_high/2.0:
  240. cuts = Rs[np.logical_and(lams >= lam, lams <= 2*lam)]
  241. vgdr[idx] = np.mean(cuts)
  242. return np.amin(vgdr)
  243. def vgdr2_eval_wsweep(
  244. qx,
  245. inc_ang,
  246. lam_low=0.25, #in nm
  247. lam_high=2,
  248. lam_pts=256,
  249. n_subs=1.52,
  250. ):
  251. """TODO: Docstring for tmm_eval.
  252. """
  253. degree = np.pi/180
  254. #lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  255. lam_inv = np.linspace(1/lam_low, 1/lam_high, num=lam_pts, endpoint=True)
  256. lams = 1.0/lam_inv
  257. Rs = np.zeros(lams.size)
  258. #Rp = np.zeros(lams.size)
  259. for lidx, lam in enumerate(lams):
  260. d_x, n_x = make_nxdx(qx=qx, n_substrate=n_subs)
  261. Rs[lidx] = 100*coh_tmm('s',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  262. #Rp[lidx] = 100*coh_tmm('p',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  263. #return Rs
  264. vgdr = 100*np.ones(lam_pts)
  265. for idx, lam in enumerate(lams):
  266. if lams[idx] <= 1:
  267. cuts = Rs[np.logical_and(lams >= lam, lams <= 2*lam)]
  268. vgdr[idx] = np.mean(cuts)
  269. return np.amin(vgdr), 400/lams[np.argmin(vgdr)]
  270. def tmm_eval_wsweep(
  271. qx,
  272. inc_ang,
  273. lam_low=0.1, #in nm
  274. lam_high=10,
  275. lam_pts=100,
  276. n_subs=1.52,
  277. ):
  278. """TODO: Docstring for tmm_eval.
  279. """
  280. degree = np.pi/180
  281. #lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  282. lam_inv = np.linspace(1/lam_low, 1/lam_high, num=lam_pts, endpoint=True)
  283. lams = 1.0/lam_inv
  284. Rs = np.zeros(lams.size)
  285. #Rp = np.zeros(lams.size)
  286. for lidx, lam in enumerate(lams):
  287. d_x, n_x = make_nxdx(qx=qx, n_substrate=n_subs)
  288. Rs[lidx] = 100*coh_tmm('s',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  289. #Rp[lidx] = 100*coh_tmm('p',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  290. return Rs
  291. # def tmm_wrapper2(arg):
  292. # args, kwargs = arg
  293. # return tmm_eval_wbk(*args, **kwargs)
  294. # def tmm_lam_parallel(
  295. # q_x,
  296. # cthick,
  297. # inc_ang,
  298. # n_par=12,
  299. # lam_low=400,
  300. # lam_high=1200,
  301. # lam_pts=100,
  302. # **kwargs):
  303. # jobs = []
  304. # pool=mp.Pool(n_par)
  305. # lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  306. # for lam in lams:
  307. # jobs.append((q_x, cthick, inc_ang, lam))
  308. # arg = [(j, kwargs) for j in jobs]
  309. # answ = np.array(pool.map(tmm_wrapper2, arg))
  310. # pool.close()
  311. # return answ[:,0], answ[:,1]
  312. # def tmm_wrapper(arg):
  313. # args, kwargs = arg
  314. # return tmm_eval_wsweep(*args, **kwargs)
  315. # def tmm_eval_parallel(q_x, cthick, n_ang= 25, n_par=10, **kwargs):
  316. # jobs = []
  317. # pool=mp.Pool(n_par)
  318. # angs = np.linspace(90, 0, endpoint=True, num=n_ang)
  319. # for ang in angs:
  320. # jobs.append((q_x, cthick, ang))
  321. # arg = [(j, kwargs) for j in jobs]
  322. # answ = np.array(pool.map(tmm_wrapper, arg))
  323. # pool.close()
  324. # return answ[:,0,:], answ[:,1,:]