makeqx.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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 digitize_qx(q_x, dlevels=2):
  99. """TODO: Docstring for digitize_qx.
  100. :q_x: TODO
  101. :returns: TODO
  102. """
  103. #bins = np.array([-0.02, 0.2, 0.4, 0.6, 0.8, 1.01])
  104. bins = np.linspace(0,1, num=dlevels+1, endpoint=True)
  105. bins[0] = -0.02
  106. bins[-1] = 1.01
  107. dig = (np.digitize(q_x, bins, right=True)) - 1
  108. act_r = np.linspace(0, 1, num=dlevels, endpoint=True)
  109. return act_r[dig]
  110. def make_nxdx(qx, cthick, wavelen, n_substrate=1.52):
  111. """TODO: Docstring for make_nxdx.
  112. :qx: TODO
  113. :n_substrate: TODO
  114. :layer_thickness: TODO
  115. :returns: TODO
  116. """
  117. num_layers = qx.size
  118. d_x = num_layers*[cthick/num_layers]
  119. d_x = [np.inf] + d_x + [np.inf]
  120. sde = LL_mixing(fH = qx,
  121. n_H = 2.58, #get_nk(datafile=matsdict[3], wavelengths=wavelen),
  122. n_L = 1.45) #get_nk(datafile=matsdict[4], wavelengths=wavelen
  123. # ))
  124. n_x = [1.0] + sde.tolist() + [n_substrate]
  125. return d_x, n_x
  126. def tmm_eval2(
  127. qx,
  128. cthick,
  129. lam_low=400, #in nm
  130. lam_high=1200,
  131. lam_pts=100,
  132. ang_low=0, #degrees
  133. ang_high=90,
  134. ang_pts=25,
  135. n_subs=1.52,
  136. ):
  137. """TODO: Docstring for tmm_eval.
  138. :qx: TODO
  139. :lam_low: TODO
  140. :#in nm
  141. lam_high: TODO
  142. :lam_pts: TODO
  143. :ang_low: TODO
  144. :#degrees
  145. ang_high: TODO
  146. :ang_pts: TODO
  147. :returns: TODO
  148. """
  149. degree = np.pi/180
  150. lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  151. thetas = np.linspace(ang_high, ang_low, endpoint=True, num=ang_pts)
  152. Rs = np.zeros((thetas.size, lams.size))
  153. Rp = np.zeros((thetas.size, lams.size))
  154. for tidx, theta in enumerate(thetas):
  155. for lidx, lam in enumerate(lams):
  156. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  157. Rs[tidx, lidx] = 100*coh_tmm('s',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  158. Rp[tidx, lidx] = 100*coh_tmm('p',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  159. return Rs, Rp
  160. def tmm_eval(
  161. qx,
  162. cthick,
  163. lam_low=400, #in nm
  164. lam_high=1200,
  165. lam_pts=100,
  166. ang_low=0, #degrees
  167. ang_high=90,
  168. ang_pts=25,
  169. n_subs=1.52,
  170. ):
  171. """TODO: Docstring for tmm_eval.
  172. :qx: TODO
  173. :lam_low: TODO
  174. :#in nm
  175. lam_high: TODO
  176. :lam_pts: TODO
  177. :ang_low: TODO
  178. :#degrees
  179. ang_high: TODO
  180. :ang_pts: TODO
  181. :returns: TODO
  182. """
  183. degree = np.pi/180
  184. lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  185. thetas = np.linspace(ang_high, ang_low, endpoint=True, num=ang_pts)
  186. Rs = np.zeros((thetas.size, lams.size))
  187. Rp = np.zeros((thetas.size, lams.size))
  188. for tidx, theta in enumerate(thetas):
  189. for lidx, lam in enumerate(lams):
  190. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  191. Rs[tidx, lidx] = 100*coh_tmm('s',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  192. Rp[tidx, lidx] = 100*coh_tmm('p',n_x,d_x, th_0=theta*degree,lam_vac=lam)
  193. return Rs, Rp
  194. def tmm_eval_wbk(
  195. qx,
  196. cthick,
  197. inc_ang,
  198. lam,
  199. n_subs=1.52
  200. ):
  201. """TODO: Docstring for tmm_eval.
  202. :qx: TODO
  203. :returns: TODO
  204. """
  205. degree = np.pi/180
  206. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  207. Rs = 100*mtmm.coh_tmm('s',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  208. # Rp = 100*coh_tmm('p',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  209. return Rs
  210. def tmm_eval_wsweep(
  211. qx,
  212. cthick,
  213. inc_ang,
  214. lam_low=400, #in nm
  215. lam_high=1200,
  216. lam_pts=100,
  217. n_subs=1.52,
  218. ):
  219. """TODO: Docstring for tmm_eval.
  220. :qx: TODO
  221. :lam_low: TODO
  222. lam_high: TODO
  223. :lam_pts: TODO
  224. :returns: TODO
  225. """
  226. degree = np.pi/180
  227. lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  228. Rs = np.zeros(lams.size)
  229. #Rp = np.zeros(lams.size)
  230. for lidx, lam in enumerate(lams):
  231. d_x, n_x = make_nxdx(qx=qx, cthick=cthick, wavelen=lam, n_substrate=n_subs)
  232. Rs[lidx] = 100*coh_tmm('s',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  233. #Rp[lidx] = 100*coh_tmm('p',n_x,d_x, th_0=inc_ang*degree,lam_vac=lam)
  234. return Rs
  235. def tmm_wrapper2(arg):
  236. args, kwargs = arg
  237. return tmm_eval_wbk(*args, **kwargs)
  238. def tmm_lam_parallel(
  239. q_x,
  240. cthick,
  241. inc_ang,
  242. n_par=12,
  243. lam_low=400,
  244. lam_high=1200,
  245. lam_pts=100,
  246. **kwargs):
  247. jobs = []
  248. pool=mp.Pool(n_par)
  249. lams = np.linspace(lam_low, lam_high, endpoint=True, num=lam_pts)
  250. for lam in lams:
  251. jobs.append((q_x, cthick, inc_ang, lam))
  252. arg = [(j, kwargs) for j in jobs]
  253. answ = np.array(pool.map(tmm_wrapper2, arg))
  254. pool.close()
  255. return answ[:,0], answ[:,1]
  256. def tmm_wrapper(arg):
  257. args, kwargs = arg
  258. return tmm_eval_wsweep(*args, **kwargs)
  259. def tmm_eval_parallel(q_x, cthick, n_ang= 25, n_par=10, **kwargs):
  260. jobs = []
  261. pool=mp.Pool(n_par)
  262. angs = np.linspace(90, 0, endpoint=True, num=n_ang)
  263. for ang in angs:
  264. jobs.append((q_x, cthick, ang))
  265. arg = [(j, kwargs) for j in jobs]
  266. answ = np.array(pool.map(tmm_wrapper, arg))
  267. pool.close()
  268. return answ[:,0,:], answ[:,1,:]