Source code for tdsxtract.optim

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Benjamin Vial
# License: MIT

import numpy as npo
from jax import vmap
from scipy.optimize import minimize

from .stack import *


[docs] def sample_transmission(epsilons, thickness, sample=None, wavelengths=None): unknown = "unknown" t = [] sample[unknown]["thickness"] = thickness def _t(params): lambda0, eps = params sample[unknown]["epsilon"] = eps t = get_transmission(sample, lambda0) return t params = wavelengths, epsilons t = vmap(_t)(params) return np.array(t)
@jit def _fmini( x, sample=None, t_exp=None, wavelengths=None, weights=(1, 0), opt_thickness=None, ): unknown = "unknown" nl = len(wavelengths) thickness = sample[unknown]["thickness"] if opt_thickness != None: thickness *= x[-1] sample[unknown]["thickness"] = thickness x_ = x[:-1] else: x_ = x epsilon = x_[:nl] + 1j * x_[nl:] gamma = 2 * pi / wavelengths thickness_tot = np.sum(np.array([k["thickness"] for lay, k in sample.items()])) phasor = np.exp(-1j * gamma * thickness_tot) t_exp_phased = t_exp * phasor t_model = sample_transmission( epsilon, thickness, sample=sample, wavelengths=wavelengths ) mse_func = np.mean( np.abs(t_exp_phased - t_model) ** 2 ) # / np.mean(np.abs(t_exp_phased) ** 2) # epsmax,epsmin = np.max((epsilon)),np.min((epsilon)) # deps= np.abs(epsmax-epsmin) # # no = np.max(np.array([deps,1e-3])) # mse_grad = np.mean(np.abs(np.gradient(epsilon) ) ** 2)/ no**2 mse_grad = np.mean(np.abs(np.gradient(epsilon)) ** 2) / np.mean( np.abs(epsilon) ** 2 ) # * np.mean(np.abs( freq/ epsilon)**2) mse = weights[0] * mse_func + weights[1] * mse_grad return mse _jit_gfunc = jit(grad(_fmini)) def _jac(x, **kwargs): return npo.array(_jit_gfunc(x, **kwargs))
[docs] def extract( sample, wavelengths, t_exp, epsilon_initial_guess=None, eps_re_min=None, eps_re_max=None, eps_im_min=None, eps_im_max=None, thickness_tol=0, opt_thickness=False, weight=1, ): h = sample["unknown"]["thickness"] nl = len(wavelengths) ones = npo.ones_like(wavelengths) # passiv = 1 - float(force_passive) if epsilon_initial_guess == None: epsilon_initial_guess = 1 + 0j eps_re0 = epsilon_initial_guess.real * ones eps_im0 = epsilon_initial_guess.imag * ones eps_re_min = float(eps_re_min) if eps_re_min is not None else None eps_re_max = float(eps_re_max) if eps_re_max is not None else None eps_im_min = float(eps_im_min) if eps_im_min is not None else None eps_im_max = float(eps_im_max) if eps_im_max is not None else None hmin, hmax = (1 - thickness_tol), (1 + thickness_tol) x0 = [eps_re0, eps_im0] if opt_thickness: x0.append(1) initial_guess = npo.float64(npo.hstack(x0)) bounds = [(eps_re_min, eps_re_max) for i in range(nl)] bounds += [(eps_im_min, eps_im_max) for i in range(nl)] if opt_thickness: bounds += [(hmin, hmax)] bounds = npo.float64(bounds) weights = (float(weight), float(1 - weight)) optthick = True if opt_thickness else None fmini_opt = lambda x: _fmini( x, sample=sample, weights=weights, t_exp=t_exp, wavelengths=wavelengths, opt_thickness=optthick, ) jac_opt = lambda x: _jac( x, sample=sample, weights=weights, t_exp=t_exp, wavelengths=wavelengths, opt_thickness=optthick, ) options = { "disp": True, "maxcor": 250, "ftol": 1e-16, "gtol": 1e-16, "eps": 1e-11, "maxfun": 15000, "maxiter": 15000, "iprint": 1, "maxls": 200, "finite_diff_rel_step": None, } opt = minimize( fmini_opt, initial_guess, bounds=bounds, tol=1e-16, options=options, jac=jac_opt, method="L-BFGS-B", ) if opt_thickness: h_opt = opt.x[-1] * h _epsopt = opt.x[:-1] else: h_opt = h _epsopt = opt.x epsilon_opt = _epsopt[:nl] + 1j * _epsopt[nl:] return epsilon_opt, h_opt, opt