def stack_mat2d(k, d, epsv, epsa, betay=0., method="4x4", mask=None): n = len(d) indices = range(n) if method.startswith("2x2"): indices = reversed(indices) verbose_level = DTMMConfig.verbose if verbose_level > 1: print("Building stack matrix.") for i in range(n): print_progress(i, n, level=verbose_level) mat = layer_mat2d(k, d[i], epsv[i], epsa[i], betay=betay, mask=mask, method=method) if i == 0: if isinstance(mat, tuple): out = tuple((m.copy() for m in mat)) else: out = mat.copy() else: if isinstance(mat, tuple): out = tuple((bdotmm(o, m) for o, m in zip(out, mat))) else: out = bdotmm(out, mat) print_progress(n, n, level=verbose_level) return out
def stack_mat(kd, epsv, epsa, beta=0, phi=0, method="4x4", out=None): """Computes a stack characteristic matrix M = M_1.M_2....M_n if method is 4x4, 4x2(2x4) and a characteristic matrix M = M_n...M_2.M_1 if method is 2x2. Note that this function calls :func:`layer_mat`, so numpy broadcasting rules apply to kd[i], epsv[i], epsa[], beta and phi. Parameters ---------- kd : array_like A sequence of phase values (layer thickness times wavenumber in vacuum). len(kd) must match len(epsv) and len(epsa). epsv : array_like A sequence of epsilon eigenvalues. epsa : array_like A sequence of optical axes orientation angles (psi, theta, phi). beta : float Beta angle of input light. phi : float Phi angle of input light. method : str One of `4x4` (4x4 berreman), `2x2` (2x2 jones) or `4x2` (4x4 single reflections) out : ndarray, optional Returns ------- cmat : ndarray Characteristic matrix of the stack. """ t0 = time.time() mat = None n = len(kd) indices = range(n) if method == "2x2": indices = reversed(indices) verbose_level = DTMMConfig.verbose if verbose_level > 1: print("Building stack matrix.") for pi, i in enumerate(range(n)): print_progress(pi, n, level=verbose_level) mat = layer_mat(kd[i], epsv[i], epsa[i], beta=beta, phi=phi, method=method, out=mat) if pi == 0: if out is None: out = mat.copy() else: out[...] = mat else: dotmm(out, mat, out) print_progress(n, n, level=verbose_level) t = time.time() - t0 if verbose_level > 1: print(" Done in {:.2f} seconds!".format(t)) return out
def reflection_mat2d(smat): verbose_level = DTMMConfig.verbose if verbose_level > 1: print("Building reflectance and transmittance matrix.") if isinstance(smat, tuple): out = [] n = len(smat) for i, s in enumerate(smat): print_progress(i, n, level=verbose_level) out.append(_reflection_mat2d(s)) print_progress(n, n, level=verbose_level) return tuple(out) else: return _reflection_mat2d(smat)
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 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