def _layers_list(optical_data, eff_data, nin, nout, nstep): """Build optical data layers list and effective data layers list. It appends/prepends input and output layers. A layer consists of a tuple of (n, thickness, epsv, epsa) where n is number of sublayers""" d, epsv, epsa = validate_optical_data(optical_data) n = len(d) substeps = np.broadcast_to(np.asarray(nstep), (n, )) layers = [(n, (t / n, ev, ea)) for n, t, ev, ea in zip(substeps, d, epsv, epsa)] #add input and output layers layers.insert(0, (1, (0., np.broadcast_to(refind2eps([nin] * 3), epsv[0].shape), np.broadcast_to(np.array( (0., 0., 0.), dtype=FDTYPE), epsa[0].shape)))) layers.append( (1, (0., np.broadcast_to(refind2eps([nout] * 3), epsv[0].shape), np.broadcast_to(np.array((0., 0., 0.), dtype=FDTYPE), epsa[0].shape)))) if eff_data is None: d_eff, epsv_eff, epsa_eff = _isotropic_effective_data(optical_data) else: d_eff, epsv_eff, epsa_eff = validate_optical_data(eff_data, homogeneous=True) eff_layers = [(n, (t / n, ev, ea)) for n, t, ev, ea in zip(substeps, d_eff, epsv_eff, epsa_eff)] eff_layers.insert( 0, (1, (0., refind2eps([nin] * 3), np.array( (0., 0., 0.), dtype=FDTYPE)))) eff_layers.append( (1, (0., refind2eps([nout] * 3), np.array((0., 0., 0.), dtype=FDTYPE)))) return layers, eff_layers
def plot_angles(data, **kwargs): """Plots eps angles for optical data or angles data. Parameters ---------- data : optical_data or material (eps) A valid optical data tuple, eps array eps : array or None, optional Specifies which eps values to plot. If not given, all data is plotted. center : bool, optional Whether to view coordinates from the center of the box. xlim : (low, high) or None, optional A tuple describing the coordinate limits in the x direction (width). ylim : (low, high) or None, optional A tuple describing the coordinate limits in the y direction (height). zlim : (low, high) or None, optional A tuple describing the coordinate limits in the z direction (layer index). ax : matplotlib.axes or None, optional If specified, plot to ax. """ if isinstance(data, tuple): d, eps, angles = validate_optical_data(data) else: angles = data director = angles2director(angles) return plot_director(director, **kwargs)
def _isotropic_effective_data(data): d, material, angles = data n = len(d) epseff = uniaxial_order(0., material).mean(axis=(0, 1, 2)) epseff = np.broadcast_to( epseff, (n, 3)).copy() #better to make copy.. to make it c contiguous aeff = np.array((0., 0., 0.)) aeff = np.broadcast_to( aeff, (n, 3)).copy() #better to make copy.. to make it c contiguous return validate_optical_data((d, epseff, aeff), homogeneous=True)
def transfer_4x4(field_data, optical_data, beta=0., phi=0., eff_data=None, nin=1., nout=1., npass=1, nstep=1, diffraction=True, reflection=1, multiray=False, norm=DTMM_NORM_FFT, smooth=SMOOTH, betamax=BETAMAX, ret_bulk=False, out=None): """Transfers input field data through optical data. See transfer_field. """ if reflection not in (1, 2, 3, 4): raise ValueError( "Invalid reflection. The 4x4 method is either reflection mode 1 or 2." ) if smooth > 1.: pass #smooth =1. elif smooth < 0: smooth = 0. verbose_level = DTMMConfig.verbose if verbose_level > 1: print(" * Initializing.") calc_reference = bool(norm & DTMM_NORM_REF) if (norm & DTMM_NORM_FFT): norm = "fft" else: if calc_reference: norm = "local" else: norm = "total" #define optical data d, epsv, epsa = validate_optical_data(optical_data) layers, eff_layers = _layers_list(optical_data, eff_data, nin, nout, nstep) #define input field data field_in, wavelengths, pixelsize = field_data #define constants ks = k0(wavelengths, pixelsize) n = len(layers) if beta is None and phi is None: ray_tracing = False beta, phi = field2betaphi(field_in, ks, multiray) else: ray_tracing = False if diffraction != 1: ray_tracing = False beta, phi = _validate_betaphi(beta, phi, extendeddim=field_in.ndim - 2) #define output field if out is None: if ret_bulk == True: bulk_out = np.zeros((n, ) + field_in.shape, field_in.dtype) bulk_out[0] = field_in field_in = bulk_out[0] field_out = bulk_out[-1] else: bulk_out = None field_out = np.zeros_like(field_in) else: out[...] = 0. if ret_bulk == True: bulk_out = out bulk_out[0] = field_in field_in = bulk_out[0] field_out = bulk_out[-1] else: bulk_out = None field_out = out indices = list(range(1, n - 1)) #if npass > 1: # field0 = field_in.copy() field0 = field_in.copy() field = field_in.copy() field_in[...] = 0. if norm == 2: #make sure we take only the forward propagating part of the field transmitted_field(field, ks, n=nin, betamax=min(betamax, nin), out=field) if calc_reference: ref = field.copy() else: ref = None i0 = field2intensity(transmitted_field(field0, ks, n=nin, betamax=betamax)) i0 = i0.sum(tuple(range(i0.ndim))[-2:]) if reflection not in (2, 4) and 0 <= diffraction and diffraction < np.inf: work_in_fft = True else: work_in_fft = False if work_in_fft: field = fft2(field, out=field) _reuse = False tmpdata = {} #:projection matrices.. set when needed if npass > 1: pin_mat = projection_matrix(field.shape[-2:], ks, epsv=refind2eps([nin] * 3), mode=+1, betamax=betamax) pout_mat = projection_matrix(field.shape[-2:], ks, epsv=refind2eps([nout] * 3), mode=+1, betamax=betamax) for i in range(npass): if verbose_level > 0: prefix = " * Pass {:2d}/{}".format(i + 1, npass) suffix = "" else: prefix = "" suffix = "{}/{}".format(i + 1, npass) _bulk_out = bulk_out direction = (-1)**i _nstep, (thickness, ev, ea) = layers[indices[0]] if direction == 1: _betamax = betamax else: _betamax = betamax for pindex, j in enumerate(indices): print_progress(pindex, n, level=verbose_level, suffix=suffix, prefix=prefix) nstep, (thickness, ev, ea) = layers[j] output_layer = (thickness * direction, ev, ea) _nstep, output_layer_eff = eff_layers[j] d, e, a = output_layer_eff output_layer_eff = d * direction, e, a if ray_tracing == True: if work_in_fft: beta, phi = field2betaphi(ifft2(field), ks, multiray) else: beta, phi = field2betaphi(field, ks, multiray) beta, phi = _validate_betaphi(beta, phi, extendeddim=field_in.ndim - 2) if calc_reference and i % 2 == 0: _nstep, (thickness_in, ev_in, ea_in) = layers[j - 1] input_layer = (thickness_in, ev_in, ea_in) ref2, refl = propagate_2x2_effective_2(ref[..., ::2, :, :], ks, input_layer, output_layer, None, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, reflection=0, betamax=_betamax, mode=direction, out=ref[..., ::2, :, :]) if bulk_out is not None: out_field = _bulk_out[j] else: out_field = field if diffraction >= 0 and diffraction < np.inf: if reflection == 4: field = propagate_4x4_effective_4(field, ks, output_layer, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, betamax=_betamax, out=out_field) elif reflection == 3: field = propagate_4x4_effective_3(field, ks, output_layer, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, betamax=_betamax, out=out_field) elif reflection == 2: field = propagate_4x4_effective_2(field, ks, output_layer, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, betamax=_betamax, out=out_field, tmpdata=tmpdata) else: field = propagate_4x4_effective_1(field, ks, output_layer, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, betamax=_betamax, out=out_field, _reuse=_reuse) else: field = propagate_4x4_full(field, ks, output_layer, nsteps=nstep, betamax=_betamax, out=out_field) _reuse = True if ref is not None: ref[..., 1::2, :, :] = jones2H(ref2, ks, betamax=_betamax, n=nout) print_progress(n, n, level=verbose_level, suffix=suffix, prefix=prefix) indices.reverse() if work_in_fft == True: field = ifft2(field) if npass > 1: #smooth = 1. - i/(npass-1.) if i % 2 == 0: if i != npass - 1: if verbose_level > 1: print(" * Normalizing transmissions.") if calc_reference: np.multiply(ref, (nin / nout)**0.5, ref) sigma = smooth * (npass - i) / (npass) if norm == "fft": field = project_normalized_fft(field, pout_mat, ref=ref, out=field) elif norm == "local": field = project_normalized_local(field, pout_mat, ref=ref, out=field) elif norm == "total": field = project_normalized_total(field, pout_mat, ref=ref, out=field) field = denoise_field(field, ks, nin, sigma, out=field) np.add(field_out, field, field_out) field = field_out.copy() else: field_in[...] = field if i != npass - 1: if verbose_level > 1: print(" * Normalizing reflections.") sigma = smooth * (npass - i) / (npass) ffield = fft2(field, out=field) ffield = dotmf(pin_mat, ffield, out=ffield) ffield = denoise_fftfield(ffield, ks, nin, sigma, out=ffield) field = ifft2(field, out=ffield) i0f = total_intensity(field) fact = ((i0 / i0f)) fact = fact[..., None, None, None] np.multiply(field, fact, out=field) np.multiply(field_out, fact, out=field_out) np.multiply(field_in, fact, out=field_in) np.subtract(field0, field, out=field) np.add(field_in, field, field_in) if calc_reference: ref = field.copy() if work_in_fft == True: field = fft2(field, out=field) else: field_out[...] = field field_in[...] = field0 #denoise(field_out, ks, nout, smooth*10, out = field_out) if ret_bulk == True: if work_in_fft: ifft2(bulk_out[1:-1], out=bulk_out[1:-1]) return bulk_out, wavelengths, pixelsize else: return field_out, wavelengths, pixelsize
def plot_material(data, eps=None, center=False, xlim=None, ylim=None, zlim=None, ax=None): """Plots material (in color) of the optical data. Parameters ---------- data : optical_data or material (eps) A valid optical data tuple, eps array eps : array or None, optional Specifies which eps values to plot. If not given, all data is plotted. center : bool, optional Whether to view coordinates from the center of the box. xlim : (low, high) or None, optional A tuple describing the coordinate limits in the x direction (width). ylim : (low, high) or None, optional A tuple describing the coordinate limits in the y direction (height). zlim : (low, high) or None, optional A tuple describing the coordinate limits in the z direction (layer index). ax : matplotlib.axes or None, optional If specified, plot to ax. """ if isinstance(data, tuple): d, material, angles = validate_optical_data(data) else: material = data if material.ndim == 3: material = material[None, ...] material = np.asarray(material, dtype="float32") assert material.ndim == 4 if eps is None: eps = unique_eps(material) else: eps = np.asarray(eps) if eps.ndim == 1: eps = eps[None, :] if ax is None: fig = plt.figure() ax = fig.add_subplot(111, projection='3d') try: #this does not work in recent versions of matplotlib ax.set_aspect('equal') except NotImplementedError: pass xx, yy, zz = _r3(material.shape[0:-1], center) #mmin, mmax = material.min(), material.max() #if mmax != mmin: # colors = (material-mmin)/(mmax-mmin) #else: # colors = material-mmin for e in eps: mask = (material[..., 0] == e[0]) & (material[..., 1] == e[1]) & ( material[..., 2] == e[2]) mask = _add_mask(mask, xx, xlim) mask = _add_mask(mask, yy, ylim) mask = _add_mask(mask, zz, zlim) xs = xx[mask] ys = yy[mask] zs = zz[mask] #cs = colors[mask,:] #ax.scatter(xs, ys, zs,depthshade = False, s = 1, marker = ".", c = cs) ax.scatter(xs, ys, zs, depthshade=False, s=1, marker=".", label=e) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') plt.legend() return ax.figure, ax