def project_normalized_fft(field, dmat, window=None, ref=None, out=None): if ref is not None: fref = fft2(ref, out=out) intensity1 = field2intensity(fref) f1 = fft2(field, out=out) else: f1 = fft2(field, out=out) intensity1 = field2intensity(f1) f2 = dotmf(dmat, f1, out=f1) intensity2 = field2intensity(f2) f3 = normalize_field(f2, intensity1, intensity2, out=f2) out = ifft2(f3, out=out) if window is not None: out = np.multiply(out, window, out=out) return out
def _transfer_ray_4x4_1_windows(windows, field, wavenumbers, layer, dmat1, dmat2, betas, phis, nsteps = 1, out = None, betamax = BETAMAX): d, epsv, epsa = layer kd = wavenumbers*d if out is None: out = np.zeros_like(field) for j in range(nsteps): field = dotmf(dmat1,field) for window, beta, phi in zip(windows, betas, phis): alpha, f = alphaf(beta,phi,epsv,epsa) p = phasem(alpha,kd[...,None,None]) e = E_mat(f, mode = None) ei = inv(e) f = field * window f = ifft2(f, out = f) f = dotmdmf(e,p,ei,f, out = f) f = fft2(field, out = f) out += f out = dotmf(dmat2,out, out = out) return out
def project_normalized_local(field, dmat, window=None, ref=None, out=None): f1 = fft2(field) f2 = dotmf(dmat, f1, out=f1) f = ifft2(f2, out=f2) pmat1 = normal_polarizer(jonesvec(transpose(f[..., ::2, :, :]))) pmat2 = -pmat1 pmat2[..., 0, 0] += 1 pmat2[..., 1, 1] += 1 #pmat1 + pmat2 = identity by definition pmat2[..., 2, 2] += 1 #pmat1 + pmat2 = identity by definition pmat2[..., 3, 3] += 1 #pmat1 + pmat2 = identity by definition if ref is not None: intensity1 = field2intensity(dotmf(pmat1, ref)) ref = dotmf(pmat2, ref) else: intensity1 = field2intensity(dotmf(pmat1, field)) ref = dotmf(pmat2, field) intensity2 = field2intensity(f) f = normalize_field(f, intensity1, intensity2) out = np.add(f, ref, out=out) if window is not None: out = np.multiply(out, window, out=out) return out
def mean_betaphi(field, k0): """Calculates mean beta and phi of a given field.""" b = blackman(field.shape[-2:]) f = fft2(field * b) #filter it with blackman.. betax, betay = betaxy(field.shape[-2:], k0) beta, phi = _fft_betaphi(f, betax, betay) return beta, phi
def propagate_4x4_full(field, wavenumbers, layer, nsteps=1, betamax=BETAMAX, out=None): shape = field.shape[-2:] d, epsv, epsa = layer kd = wavenumbers * d / nsteps if out is None: out = np.empty_like(field) out_af = None pm = None ii, jj = np.meshgrid(range(shape[0]), range(shape[1]), copy=False, indexing="ij") for step in range(nsteps): for i in range(len(wavenumbers)): ffield = fft2(field[..., i, :, :, :]) ofield = np.zeros_like(out[..., i, :, :, :]) b, p = betaphi(shape, wavenumbers[i]) mask = b < betamax amplitude = ffield[..., mask] betas = b[mask] phis = p[mask] iind = ii[mask] jind = jj[mask] for bp in sorted(zip(range(len(betas)), betas, phis, iind, jind), key=lambda el: el[1], reverse=False): #for j,bp in enumerate(zip(betas,phis,iind,jind)): j, beta, phi, ieig, jeig = bp out_af = alphaffi(beta, phi, epsv, epsa, out=out_af) alpha, f, fi = out_af pm = phasem(alpha, kd[i], out=pm) w = eigenwave(amplitude.shape[:-1] + shape, ieig, jeig, amplitude=amplitude[..., j]) w = dotmdmf(f, pm, fi, w, out=w) np.add(ofield, w, ofield) out[..., i, :, :, :] = ofield field = out return out
def wave2eigenwave(wave, out=None): """Converts any wave to nearest eigenwave""" wave = np.asarray(wave) if out is None: out = np.empty(shape=wave.shape, dtype=CDTYPE) shape = wave.shape assert wave.ndim >= 2 if len(shape) > 2: h = shape[-2] w = shape[-1] wave = wave.reshape(-1) #flatten n = len(wave) // h // w wave = wave.reshape((n, h, w)) o = out.reshape((n, h, w)) else: o = out s = np.abs(fft.fft2(wave))**2 if len(shape) == 2: s = s[None, ...] o = out[None, ...] for i, a in enumerate(s): avg = a.sum() indices = np.argmax(a) ii, jj = np.unravel_index(indices, a.shape) eigenwave(a.shape, ii, jj, amplitude=avg**0.5, out=o[i]) return out
def _transfer_ray_4x4_1(field, wavenumbers, layer, dmat1, dmat2, beta=0, phi=0, nsteps=1, betamax=BETAMAX, out=None): d, epsv, epsa = layer kd = wavenumbers * d alpha, f = alphaf(beta, phi, epsv, epsa) p = phasem(alpha, kd[..., None, None]) e = E_mat(f, mode=None) ei = inv(e) for j in range(nsteps): field = dotmf(dmat1, field, out=out) field = ifft2(field, out=field) field = dotmdmf(e, p, ei, field, out=field) field = fft2(field, out=field) field = dotmf(dmat2, field, out=out) return field
def diffract(fieldv, dmat, window=None, out=None): f = fft2(fieldv, out=out) f2 = dotmf(dmat, f, out=f) out = ifft2(f2, out=out) if window is not None: out = np.multiply(out, window, out=out) return out
def filter_eps(eps, k, betamax=1): eps = np.moveaxis(eps, -1, -3) feps = fft2(eps) beta, phi = betaphi(feps.shape[-2:], k) mask = beta > betamax feps[..., mask] = 0. eps = ifft2(feps) eps = np.moveaxis(eps, -3, -1) return eps
def diffract(field, dmat, window=None, input_fft=False, output_fft=False, out=None): """Takes input field vector and diffracts it Parameters ---------- field : (...,4,:,:) array Input field array. dmat : array Diffraction matrix. Use :func:`field_diffraction_matrix`to create one window : array, optional A window function applied to the result input_fft : bool Specifies whether input field array is the Fourier transform of the field. By default, input is assumed to be in real space. output_fft : bool Specifies whether the computed field array is the Fourier transform. By default, output is assumed to be in real space. out : ndarray, optional If specified, store the results here. Returns ------- field : (...,4,:,:) array Diffracted field in real space (if output_fft == False )or in fft spaace (if output_fft == True). """ if not input_fft: field = fft2(field, out=out) out = field if dmat is not None: out = dotmf(dmat, field, out=out) else: #make it work for dmat = None input... so just copy data if out is None: out = field.copy() else: if out is not field: out[...] = field if not output_fft: out = ifft2(out, out=out) if window is not None: if output_fft: raise ValueError( "Cannot use window function if ouput is fft field.") out = np.multiply(out, window, out=out) return out
def project_normalized_total(field, dmat, window=None, ref=None, out=None): if ref is not None: i1 = total_intensity(ref) else: i1 = total_intensity(field) f1 = fft2(field, out=out) f2 = dotmf(dmat, f1, out=f1) out = ifft2(f2, out=out) i2 = total_intensity(out) out = normalize_field_total(out, i1, i2, out=out) if window is not None: out = np.multiply(out, window, out=out) return out
def denoise_field(field, wavenumbers, beta, smooth=1, filter_func=exp_notch_filter, out=None): """Denoises field by attenuating modes around the selected beta parameter. """ ffield = fft2(field, out=out) ffield = denoise_fftfield(ffield, wavenumbers, beta, smooth=smooth, filter_func=filter_func, out=ffield) return ifft2(ffield, out=ffield)
def apply_mode_jonesmat(pmat, field, out=None): """Multiplies matrix with field data in fft space. Parameters ---------- pmat : array A 4x4 jones matrix of shape (...,:,:,4,4) for field data or 2x2 jones matrix of shape (...,:,:,2,2) for E-field data or field : array Field data array of shape (...,4,:,:) or (...,2,:,:). out : ndarray, optional If specified, the results are written here. Returns ------- out : array Computed field array of shape (...,4,:,:) or (...,2,:,:). """ fft = fft2(field, out=out) pfft = dotmf(pmat, fft, out=fft) return ifft2(fft, out=pfft)
def field2modes(field, k0, betamax=BETAMAX): """Converts 2D field array to modes array. Parameters ---------- field : ndarray or tuple of ndarrays Input field array (or tuple of input fields for each wavenumber). The shape of the input arrays must be (...,4,:,:) representing. k0 : float or a sequence of floats Defines the wavenumber. Fol multi-wavelength data, this must be a sequence of wawenumbers betamax : float, optional The beta cutoff parameter. Returns ------- mask, modes : ndarray, ndarray or ndarray, tuple of ndarrays For a single-wavelength data it returns the mask array specifying the mode indices and modes coefficients array. For multi-wavelength data the modes is a tuple of ndarrays for each of the wavelengths. Length of the mask in this case equals length of the wavenumbers. """ if isinstance(field, tuple): out = tuple( (field2modes(field[i], k0[i], betamax) for i in range(len(field)))) mask = tuple(o[0] for o in out) modes = tuple(o[1] for o in out) return mask, modes f = fft2(field) k0 = np.asarray(k0) mask = eigenmask(f.shape[-2:], k0, betamax) if k0.ndim == 0: return mask, np.moveaxis(f[..., mask], -2, -1) else: return mask, tuple((np.moveaxis(f[..., i, :, :, :][..., mask[i]], -2, -1) for i in range(len(k0))))
def _calculate_specter_mode(self, recalc=False, **params): self.set_parameters(**params) if self.ofield is None: recalc = True #first time only trigger calculation if recalc or self._has_parameter_updated("analyzer", "sample"): sample = self.sample if self.sample is not None else 0. if self.analyzer is not None: angle = -np.pi / 180 * (self.analyzer - sample) c, s = np.cos(angle), np.sin(angle) self.pmat = mode_polarizer(self.ifield.shape[-2:], self.ks, jones=(c, s), epsv=self.epsv, epsa=self.epsa, betamax=self.betamax) if self.pmode != "mode": self.pmat = self.pmat[..., 0:1, 0:1, :, :] if recalc or self._has_parameter_updated("focus"): if self.mode is None: self.ffield = fft2(self.ifield[self.focus]) else: self.dmat = field_diffraction_matrix(self.ifield.shape[-2:], self.ks, d=0, epsv=self.epsv, epsa=self.epsa, mode=self.mode, betamax=self.betamax) self.ffield = fft2(self.ifield[self.focus]) recalc = True #trigger update of self.data if recalc or self._has_parameter_updated("sample", "polarizer"): sample = self.sample if self.sample is not None else 0. if self.polarizer is not None: angle = -np.pi / 180 * (self.polarizer - sample) c, s = np.cos(angle), np.sin(angle) self.data = _redim(self.ffield, ndim=6) x = c * self.data[:, 0] y = s * self.data[:, 1] self.data = x + y else: self.data = _redim(self.ffield, ndim=5) if recalc or self._has_parameter_updated( "analyzer", "sample", "polarizer", "focus", "intensity"): if self.dmat is not None: pmat = dotmm(self.pmat, self.dmat) else: pmat = self.pmat self.ofield = dotmf(pmat, self.data, out=self.ofield) self.ofield = ifft2(self.ofield, out=self.ofield) for i, data in enumerate(self.ofield): if i == 0: self.specter = field2specter(data) else: self.specter += field2specter(data) recalc = True if recalc or "intensity" in self._updated_parameters: self._updated_parameters.clear() self._updated_parameters.add( "intensity") #trigger calculate_image call else: self._updated_parameters.clear() return self.specter
def ffield(self): if self._ffield is None: self._ffield = fft2(self.ifield[self.focus]) return self._ffield
def _calculate_specter_mode(self, recalc=False, **params): self.set_parameters(**params) if self.ofield is None: recalc = True #first time only trigger calculation if recalc or self._has_parameter_updated("sample", "polarizer"): sample = self.sample if self.sample is not None else 0. if self.polarizer is not None: if self.ffield is None: self.ffield = fft2(self.ifield) angle = -np.pi / 180 * (self.polarizer - sample) c, s = np.cos(angle), np.sin(angle) self.data = _redim(self.ffield, ndim=6) x = c * self.data[:, 0] y = s * self.data[:, 1] self.data = x + y else: self.data = _redim(self.ffield, ndim=5) if recalc or self._has_parameter_updated("focus"): if self.diffraction == True or self.mode is not None: #if mode is selected, we need to project the field using diffraction d = 0 if self.focus is None else self.focus self.dmat = field_diffraction_matrix(self.ifield.shape[-2:], self.ks, d=d, epsv=self.epsv, epsa=self.epsa, mode=self.mode, betamax=self.betamax) else: self.dmat = np.asarray(np.diag((1, 1, 1, 1)), CDTYPE) if recalc or self._has_parameter_updated("analyzer", "sample"): sample = self.sample if self.sample is not None else 0. if self.analyzer is not None: angle = -np.pi / 180 * (self.analyzer - sample) c, s = np.cos(angle), np.sin(angle) self.pmat = mode_polarizer(self.ifield.shape[-2:], self.ks, jones=(c, s), epsv=self.epsv, epsa=self.epsa, betamax=self.betamax) else: self.pmat = None if recalc or self._has_parameter_updated( "analyzer", "sample", "polarizer", "focus", "intensity"): tmat = None if self.pmat is not None and self.dmat is not None: tmat = dotmm(self.pmat, self.dmat) if self.pmat is None and self.dmat is not None: tmat = self.dmat if self.pmat is not None and self.dmat is None: tmat = self.pmat if tmat is not None: self.ofield = dotmf(tmat, self.data, out=self.ofield) self.ofield = ifft2(self.ofield, out=self.ofield) for i, data in enumerate(self.ofield): if i == 0: self.specter = field2specter(data) else: self.specter += field2specter(data) recalc = True if recalc or "intensity" in self._updated_parameters: self._updated_parameters.clear() self._updated_parameters.add( "intensity") #trigger calculate_image call else: self._updated_parameters.clear() return self.specter
def ffield(self): if self._ffield is None: self._ffield = fft2(self.ifield) return self._ffield
def transfer_2x2(field_data, optical_data, beta=None, phi=None, eff_data=None, nin=1., nout=1., npass=1, nstep=1, diffraction=True, reflection=True, multiray=False, split_diffraction=False, betamax=BETAMAX, ret_bulk=False, out=None): """Tranfers input field data through optical data using the 2x2 method See transfer_field for documentation. """ if reflection not in (0, 1, 2): raise ValueError( "Invalid reflection. The 2x2 method supports reflection mode 0,1 or 2." ) verbose_level = DTMMConfig.verbose if verbose_level > 1: print(" * Initializing.") #create layers lists layers, eff_layers = _layers_list(optical_data, eff_data, nin, nout, nstep) #define input field data field_in, wavelengths, pixelsize = field_data #wavenumbers ks = k0(wavelengths, pixelsize) n = len(layers) - 1 #number of interfaces 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 + 1, ) + 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(n)) #make sure we take only the forward propagating part of the field if diffraction: field0 = transmitted_field(field_in, ks, n=nin, betamax=betamax) else: field0 = transmitted_field_direct(field_in, beta, phi, n=nin) field = field0[..., ::2, :, :].copy() if npass > 1: if reflection == 0: raise ValueError( "Reflection mode `0` not compatible with npass > 1") field_in[ ...] = field0 #modify input field so that it has no back reflection #keep reference to reflected waves refl = np.zeros(shape=(n + 1, ) + field.shape[:-3] + (2, ) + field.shape[-2:], dtype=field.dtype) else: #no need to store reflected waves refl = [None] * n if reflection in (0, 1) 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) tmpdata = {} for i in range(npass): if verbose_level > 0: prefix = " * Pass {:2d}/{}".format(i + 1, npass) suffix = "" else: prefix = "" suffix = "{}/{}".format(i + 1, npass) if i > 0: field[...] = 0. direction = (-1)**i _nstep, (thickness, ev, ea) = layers[indices[0]] for pindex, j in enumerate(indices): print_progress(pindex, n, level=verbose_level, suffix=suffix, prefix=prefix) jin = j + (1 - direction) // 2 jout = j + (1 + direction) // 2 _nstep, (thickness, ev, ea) = layers[jin] input_layer = (thickness, ev, ea) nstep, (thickness, ev, ea) = layers[jout] output_layer = (thickness * direction, ev, ea) _nstep, input_layer_eff = eff_layers[jin] _nstep, output_layer_eff = eff_layers[jout] d, e, a = input_layer_eff input_layer_eff = d * direction, e, a d, e, a = output_layer_eff output_layer_eff = d * direction, e, a if jout == 0: bulk = field_in elif jout == len(indices): bulk = field_out else: if bulk_out is None: bulk = None else: bulk = bulk_out[jout] 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 diffraction >= 0 and diffraction < np.inf: if reflection <= 1: field, refli = propagate_2x2_effective_1( field, ks, input_layer, output_layer, input_layer_eff, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, split_diffraction=split_diffraction, reflection=reflection, betamax=betamax, mode=direction, refl=refl[j], bulk=bulk, tmpdata=tmpdata) else: field, refli = propagate_2x2_effective_2( field, ks, input_layer, output_layer, input_layer_eff, output_layer_eff, beta=beta, phi=phi, nsteps=nstep, diffraction=diffraction, split_diffraction=split_diffraction, reflection=reflection, betamax=betamax, mode=direction, refl=refl[j], bulk=bulk, tmpdata=tmpdata) else: field, refli = propagate_2x2_full(field, ks, output_layer, input_layer=input_layer, nsteps=1, reflection=reflection, mode=direction, betamax=betamax, refl=refl[j], bulk=bulk) print_progress(n, n, level=verbose_level, suffix=suffix, prefix=prefix) indices.reverse() if ret_bulk == True: return bulk_out, wavelengths, pixelsize else: return field_out, wavelengths, pixelsize
def _field2modes(field, k0, betamax=BETAMAX): f = fft2(field) mask = eigenmask(f.shape[-2:], k0, betamax) f = f[mask] return np.moveaxis(f, -2, -1)
def field2jones(field, ks=None, beta=None, phi=None, epsv=(1., 1., 1.), epsa=(0., 0., 0.), mode=+1, input_fft=False, output_fft=False, betamax=BETAMAX): """Converts (..., 4,n,m) field array to (..., 2,n,m) jones array The conversion is done either in reciprocal space (default) or in real space, if you provide the beta or phi parameter. Parameters ---------- field : ndarray Input field array data of shape (..., 4,n,m). ks : array A list of k-values (wave numbers). Required if beta and phi are not provided. beta : float, optional If set, it defines the field beta parameter, conversion is then done in real space. phi : float, optional If set, it defines the field phi parameter, conversion is then done in real space. epsv : array The epsilon eigenvalues of the medium epsv : array The Euler rotation angles. mode : [+1 | -1] Propagation mode, +1 (forward) by default input_fft : bool Specifies whether input array is fft data or not. output_fft : bool Specifies whether output array is fft data or not. betamax : float Defines the betamax parameter if transformation is done in Fourier space. Returns ------- jones : ndarray Output jones array of shape (..., 2,n,m). """ modal = beta is None and phi is None if modal and ks is None: raise ValueError( "For modal fields, you need to define the wave number(s).") elif not modal and ks is not None: import warnings warnings.warn( "`ks`, was set, although it is not required - field is not modal", UserWarning) field = np.asarray(field) out = np.empty(field.shape[:-3] + (2, ) + field.shape[-2:], field.dtype) if input_fft == False and modal: field = fft2(field) elif input_fft == True and not modal: field = ifft2(field) shape = field.shape[-3:] if modal: a, fmat = diffraction_alphaf(shape, ks, epsv, epsa, betamax=betamax) else: a, fmat, = alphaf(beta, phi, epsv, epsa) fvec = field2fvec(field) evec = field2fvec(out) evec[...] = fvec2E(fvec, fmat=fmat, mode=mode) if output_fft == False and modal: ifft2(out, out=out) elif output_fft == True and not modal: fft2(out, out=out) return out
def apply_mode_polarizer(pmat, field, out=None): """Multiplies mode polarizer with field data in fft space.""" fft = fft2(field, out=out) pfft = dotmf(pmat, fft, out=fft) return ifft2(fft, out=pfft)
def propagate_4x4_effective_4(field, wavenumbers, layer, effective_layer, beta=0, phi=0, nsteps=1, diffraction=True, betamax=BETAMAX, out=None): d_eff, epsv_eff, epsa_eff = effective_layer if diffraction <= 1: if diffraction != 0: dmat = corrected_field_diffraction_matrix(field.shape[-2:], wavenumbers, beta, phi, d=d_eff, epsv=epsv_eff, epsa=epsa_eff, betamax=betamax) else: dmat = None return _transfer_ray_4x4_4(field, wavenumbers, layer, beta=beta, phi=phi, nsteps=nsteps, dmat=dmat, out=out) else: fout = np.zeros_like(field) _out = None field = fft2(field) try: broadcast_shape = beta.shape beta = beta[..., 0] phi = phi[..., 0] except IndexError: broadcast_shape = () windows, (betas, phis) = fft_mask(field.shape, wavenumbers, int(diffraction), betax_off=beta * np.cos(phi), betay_off=beta * np.sin(phi), betamax=betamax) n = len(windows) betas = betas.reshape((n, ) + broadcast_shape) phis = phis.reshape((n, ) + broadcast_shape) if diffraction != 0: dmats = corrected_field_diffraction_matrix(field.shape[-2:], wavenumbers, betas, phis, d=d_eff, epsv=epsv_eff, epsa=epsa_eff) else: dmats = [None] * n for window, b, p, dmat in zip(windows, betas, phis, dmats): fpart = np.multiply(field, window, out=_out) fpart_re = ifft2(fpart, out=fpart) _out = _transfer_ray_4x4_4(fpart_re, wavenumbers, layer, beta=b, phi=p, nsteps=nsteps, dmat=dmat) fout = np.add(fout, _out, out=fout) # for window, b, p in zip(windows, betas, phis): # fpart = field * window # fpart_re = ifft2(fpart) # # b = b.reshape(beta_shape) # p = p.reshape(beta_shape) # # if diffraction != 0: # dmat = corrected_field_diffraction_matrix(field.shape[-2:], wavenumbers, b,p, d=d_eff, # epsv = epsv_eff, epsa = epsa_eff) # else: # dmat = None # # _out = _transfer_ray_4x4_2(fpart_re, wavenumbers, layer, # beta = b, phi = p, nsteps = nsteps, # dmat = dmat,_reuse = _reuse) # fout += _out if out is not None: out[...] = fout else: out = fout return out
def propagate_2x2_full(field, wavenumbers, layer, input_layer=None, nsteps=1, mode=+1, reflection=True, betamax=BETAMAX, refl=None, bulk=None, out=None): shape = field.shape[-2:] d, epsv, epsa = layer if input_layer is not None: d_in, epsv_in, epsa_in = input_layer kd = wavenumbers * d / nsteps if out is None: out = np.empty_like(field) ii, jj = np.meshgrid(range(shape[0]), range(shape[1]), copy=False, indexing="ij") for step in range(nsteps): for i in range(len(wavenumbers)): ffield = fft2(field[..., i, :, :, :]) ofield = np.zeros_like(out[..., i, :, :, :]) b, p = betaphi(shape, wavenumbers[i]) mask = b < betamax amplitude = ffield[..., mask] betas = b[mask] phis = p[mask] iind = ii[mask] jind = jj[mask] if bulk is not None: obulk = bulk[..., i, :, :, :] if refl is not None: tampl = fft2(refl[..., i, :, :, :])[..., mask] orefl = refl[..., i, :, :, :] orefl[...] = 0. for bp in sorted(zip(range(len(betas)), betas, phis, iind, jind), key=lambda el: el[1], reverse=False): #for j,bp in enumerate(zip(betas,phis,iind,jind)): j, beta, phi, ieig, jeig = bp out_af = alphaf(beta, phi, epsv, epsa) alpha, fmat_out = out_af e = E_mat(fmat_out, mode=mode) ei0 = inv(e) ei = ei0 pm = phase_mat(alpha, kd[i, None, None], mode=mode) w = eigenwave(amplitude.shape[:-1] + shape, ieig, jeig, amplitude=amplitude[..., j]) if step == 0 and reflection != False: alphain, fmat_in = alphaf(beta, phi, epsv_in, epsa_in) if refl is not None: ei, eri = Etri_mat(fmat_in, fmat_out, mode=mode) ein = E_mat(fmat_in, mode=-1 * mode) t = eigenwave(amplitude.shape[:-1] + shape, ieig, jeig, amplitude=tampl[..., j]) r = dotmf(eri, w) r = dotmf(ein, r, out=r) np.add(orefl, r, orefl) w = dotmf(ei, w, out=w) t = dotmf(ei0, t, out=t) w = np.add(t, w, out=w) else: ei = Eti_mat(fmat_in, fmat_out, mode=mode) w = dotmf(ei, w, out=w) w = dotmf(dotmd(e, pm), w, out=w) np.add(ofield, w, ofield) else: w = dotmdmf(e, pm, ei, w, out=w) np.add(ofield, w, ofield) if bulk is not None: e2h = E2H_mat(fmat_out, mode=mode) obulk[..., 1::2, :, :] += dotmf(e2h, w) obulk[..., ::2, :, :] += w out[..., i, :, :, :] = ofield field = out return out, refl
def propagate_2x2_effective_2(field, wavenumbers, layer_in, layer_out, effective_layer_in, effective_layer_out, beta=0, phi=0, nsteps=1, diffraction=True, split_diffraction=False, reflection=True, betamax=BETAMAX, mode=+1, refl=None, bulk=None, out=None, tmpdata=None): shape = field.shape[-2:] d_eff, epsv_eff, epsa_eff = effective_layer_out if diffraction <= 1: if diffraction: dmat = corrected_E_diffraction_matrix(shape, wavenumbers, beta, phi, d=d_eff, epsv=epsv_eff, epsa=epsa_eff, mode=mode, betamax=betamax) else: dmat = None return _transfer_ray_2x2_2(field, wavenumbers, layer_in, layer_out, dmat=dmat, beta=beta, phi=phi, nsteps=nsteps, reflection=reflection, betamax=betamax, mode=mode, refl=refl, bulk=bulk, out=out, tmpdata=tmpdata) else: fout = 0. fpart = None ffield = fft2(field) if refl is not None: frefl = fft2(refl) _refl = 0. else: _refl = None try: broadcast_shape = beta.shape beta = beta[..., 0] phi = phi[..., 0] except IndexError: broadcast_shape = () windows, (betas, phis) = fft_mask(field.shape, wavenumbers, int(diffraction), betax_off=beta * np.cos(phi), betay_off=beta * np.sin(phi), betamax=betamax) n = len(windows) betas = betas.reshape((n, ) + broadcast_shape) phis = phis.reshape((n, ) + broadcast_shape) if split_diffraction == False: dmats = corrected_E_diffraction_matrix(shape, wavenumbers, betas, phis, d=d_eff, epsv=epsv_eff, epsa=epsa_eff, mode=mode, betamax=betamax) idata = zip(windows, betas, phis, dmats) else: idata = zip(windows, betas, phis) for data in idata: if split_diffraction == False: window, beta, phi, dmat = data else: window, beta, phi = data dmat = corrected_E_diffraction_matrix(shape, wavenumbers, beta, phi, d=d_eff, epsv=epsv_eff, epsa=epsa_eff, mode=mode, betamax=betamax) fpart = np.multiply(ffield, window, out=fpart) fpart_re = ifft2(fpart, out=fpart) if refl is not None: reflpart = frefl * window reflpart_re = ifft2(reflpart) else: reflpart_re = None _out, __refl = _transfer_ray_2x2_2(fpart_re, wavenumbers, layer_in, layer_out, dmat=dmat, beta=beta, phi=phi, nsteps=nsteps, betamax=betamax, reflection=reflection, mode=mode, bulk=bulk, out=out, refl=reflpart_re, tmpdata=tmpdata) fout += _out if refl is not None and reflection != 0: _refl += __refl if out is not None: out[...] = fout else: out = fout if refl is not None: refl[...] = _refl return out, refl
def _transfer_ray_2x2_1(fft_field, wavenumbers, layer, effective_layer_in, effective_layer_out, dmat1, dmat2, beta=0, phi=0, nsteps=1, mode=+1, reflection=True, betamax=BETAMAX, refl=None, bulk=None, out=None, tmpdata=None): _out = {} if tmpdata is None else tmpdata #fft_field = fft2(fft_field, out = out) shape = fft_field.shape[-2:] d_in, epsv_in, epsa_in = effective_layer_in d_out, epsv_out, epsa_out = effective_layer_out if reflection: tmat, rmat = E_tr_matrix(shape, wavenumbers, epsv_in=epsv_in, epsa_in=epsa_in, epsv_out=epsv_out, epsa_out=epsa_out, mode=mode, betamax=betamax) d, epsv, epsa = layer alpha, fmat = alphaf(beta, phi, epsv, epsa, out=_out.get("alphaf")) e = E_mat(fmat, mode=mode, copy=False) #2x2 E-only view of fmat ei = inv(e, out=_out.get("ei")) # kd = wavenumbers * d p = phase_mat(alpha, kd[..., None, None], mode=mode, out=_out.get("p")) if tmpdata is not None: _out["alphaf"] = alpha, fmat _out["ei"] = ei _out["p"] = p for j in range(nsteps): if j == 0 and reflection: #reflect only at the beginning if refl is not None: trans = refl.copy() refl = dotmf(rmat, fft_field, out=refl) fft_field = dotmf(tmat, fft_field, out=out) fft_field = np.add(fft_field, trans, out=fft_field) if mode == -1 and bulk is not None: field = ifft2(fft_field) e2h = E2H_mat(fmat, mode=mode) bulk[..., ::2, :, :] += field bulk[..., 1::2, :, :] += dotmf(e2h, field, out=field) fft_field = dotmf(dmat1, fft_field, out=fft_field) out = fft_field else: fft_field = dotmf(tmat, fft_field, out=out) fft_field = dotmf(dmat1, fft_field, out=fft_field) out = fft_field else: if dmat1 is not None: fft_field = dotmf(dmat1, fft_field, out=out) out = fft_field field = ifft2(fft_field, out=out) field = dotmdmf(e, p, ei, field, out=field) fft_field = fft2(field, out=field) if dmat2 is not None: fft_field = dotmf(dmat2, fft_field, out=fft_field) #return fft_field, refl #out = ifft2(fft_field, out = out) if mode == +1 and bulk is not None: field = ifft2(fft_field) e2h = E2H_mat(fmat, mode=mode) bulk[..., 1::2, :, :] += dotmf(e2h, field) bulk[..., ::2, :, :] += field return fft_field, refl
def jones2field(jones, ks, beta=None, phi=None, epsv=(1., 1., 1.), epsa=(0., 0., 0.), mode=+1, input_fft=False, output_fft=False, betamax=BETAMAX): """Converts (..., 2,n,m) jones array to (..., 4,n,m) field array The conversion is done either in reciprocal space (default) or in real space, if you provide the beta or phi parameter. Parameters ---------- jones : ndarray Input jones array data of shape (..., 2,n,m). ks : array A list of k-values (wave numbers). beta : float, optional If set, it defines the field beta parameter, conversion is then done in real space. phi : float, optional If set, it defines the field phi parameter, conversion is then done in real space. epsv : array The epsilon eigenvalues of the medium epsv : array The Euler rotation angles. mode : [+1 | -1] Propagation mode, +1 (forward) by default input_fft : bool Specifies whether input array is fft data or not. output_fft : bool Specifies whether output array is fft data or not. betamax : float Defines the betamax parameter if transformation is done in Fourier space. Returns ------- field : ndarray Output field array of shape (..., 4,n,m). """ jones = np.asarray(jones) modal = beta is None and phi is None out = np.empty(jones.shape[:-3] + (4, ) + jones.shape[-2:], jones.dtype) if input_fft == False and modal: jones = fft2(jones) elif input_fft == True and not modal: jones = ifft2(jones) shape = jones.shape[-3:] if modal: a, fmat = diffraction_alphaf(shape, ks, epsv, epsa, betamax=betamax) else: a, fmat, = alphaf(beta, phi, epsv, epsa) fvec = field2fvec(out) jvec = field2fvec(jones) E2fvec(jvec, fmat=fmat, mode=mode, out=fvec) if output_fft == False and modal: ifft2(out, out=out) elif output_fft == True and not modal: fft2(out, out=out) return out
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