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 eigenwave(shape, i, j, amplitude=None, out=None): """Returns a planewave with a given fourier coefficient indices i and j. Parameters ---------- shape : (...,int,int) Shape (height, width) of the plane eigenwave. i : int i-th index of the fourier coefficient j : float j-th index of the fourier coefficient amplitude : complex, optional Amplitude of the fourier mode. If not specified it is set so that the amplitude in real space equals one. out : ndarray, optional Output array. Returns ------- out : array Plane wave array of shape (...,height,width). """ if out is None: f = np.zeros(shape, dtype=CDTYPE) else: f = np.asarray(out) f[...] = 0. if amplitude is None: amplitude = np.multiply.reduce(shape[-2:]) f[..., i, j] = amplitude return fft.ifft2(f, out=out)
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 _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 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 eigenwave(shape, i, j, amplitude=None, out=None): """Returns a planewave with a given fourier coefficient indices i and j. Parameters ---------- shape : (int,int) Shape of the plane eigenwave. i : int i-th index of the fourier coefficient j : float j-th index of the fourier coefficient amplitude : complex Amplitude of the fourier mode. out : ndarray, optional Output array Returns ------- array Plane wave array. """ if out is None: f = np.zeros(shape, dtype=CDTYPE) else: f = np.asarray(out) f[...] = 0. if amplitude is None: amplitude = np.multiply.reduce(shape[-2:]) f[..., i, j] = amplitude return fft.ifft2(f, out=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 modes2field(mask, modes, out=None): """Inverse of field2modes. Takes the output of field2modes and recunstructs the field array. Parameters ---------- mask : ndarray Mask array, as returned by field2modes modes : ndarray or tuple of ndarrays Modes array or a tuple of modes array (in case of multi-wavelength data). """ out = modes2ffield(mask, modes, out=out) return ifft2(out, out)
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 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 _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 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 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 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 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 _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 _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 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 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 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