_REFIND_DECL = [(NF32DTYPE[:], NF32DTYPE[:]), (NF64DTYPE[:], NFDTYPE[:]), (NC64DTYPE[:], NC64DTYPE[:]), (NC128DTYPE[:], NCDTYPE[:])] @numba.njit(_REFIND_DECL, cache=NUMBA_CACHE) def _refind2eps(refind, out): out[0] = refind[0]**2 out[1] = refind[1]**2 out[2] = refind[2]**2 _REFIND_DECL = [ NF32DTYPE(NF32DTYPE), NFDTYPE(NF64DTYPE), NC64DTYPE(NC64DTYPE), NCDTYPE(NC128DTYPE) ] @numba.vectorize(_REFIND_DECL, cache=NUMBA_CACHE) def refind2eps(refind): """Converts refractive index to epsilon""" return refind**2 _EPS_DECL = [(NF32DTYPE, NF32DTYPE[:], NF32DTYPE[:]), (NF64DTYPE, NF64DTYPE[:], NFDTYPE[:]), (NF32DTYPE, NC64DTYPE[:], NC64DTYPE[:]), (NF64DTYPE, NC128DTYPE[:], NCDTYPE[:])]
# D65 standard light 5nm specter D65PATH = os.path.join(DATAPATH, "D65.dat" ) #: color matrix for sRGB color space in D65 reference white XYZ2RGBD65 = np.array([[ 3.2404542, -1.5371385, -0.4985314], [-0.9692660, 1.8760108, 0.0415560], [ 0.0556434, -0.2040259, 1.0572252]]) RGB2XYZ = np.linalg.inv(XYZ2RGBD65) #Srgb tranfer function constants SRGBIGAMMA = 1/2.4 SRGBSLOPE = 12.92 SRGBLINPOINT = 0.0031308 SRGBA = 0.055 @numba.vectorize([NFDTYPE(NFDTYPE, NFDTYPE)], nopython = True, target = NUMBA_TARGET, cache = NUMBA_CACHE) def apply_gamma(value, gamma): """apply_gamma(value, gamma) Applies standard gamma function (transfer function) to the given (linear) data. Parameters ---------- value : float Input value gamma : float Gamma factor""" if value > 1.: return 1. if value < 0: return 0.
# D65 standard light 5nm specter D65PATH = os.path.join(DATAPATH, "D65.dat") #: color matrix for sRGB color space in D65 reference white XYZ2RGBD65 = np.array([[3.2404542, -1.5371385, -0.4985314], [-0.9692660, 1.8760108, 0.0415560], [0.0556434, -0.2040259, 1.0572252]]) RGB2XYZ = np.linalg.inv(XYZ2RGBD65) #Srgb tranfer function constants SRGBIGAMMA = 1 / 2.4 SRGBSLOPE = 12.92 SRGBLINPOINT = 0.0031308 SRGBA = 0.055 @numba.vectorize([NFDTYPE(NFDTYPE, NFDTYPE)], nopython=True, target=NUMBA_TARGET, cache=NUMBA_CACHE) def apply_gamma(value, gamma): """apply_gamma(value, gamma) Applies standard gamma function (transfer function) to the given (linear) data. Parameters ---------- value : float Input value gamma : float Gamma factor""" if value > 1.:
def _tensor_eig(tensor, is_real, eig, vec): """Computes eigenvalues of a tensor using analytical noniterative algorithm adapted from A Robust Eigensolver for 3 × 3 Symmetric Matrices by David Eberly @ Geometric Tools. Input array is overwritten. """ #if norm of the offdiagonal elements is smaller than this, treat the #tensor as a diagonal tensor. This improves handling of real diagonal epsilon #data treated as complex data, where the complex part introduces unwanted # rotations of the eigenframe, in particular when working with floats. normtol = 1e-12 m1 = max(abs(tensor[0, 0]), abs(tensor[1, 1])) m2 = max(abs(tensor[2, 2]), abs(tensor[0, 1])) m3 = max(abs(tensor[0, 2]), abs(tensor[1, 2])) scale = max(max(m1, m2), m3) if scale == 0.: #zero matrix.. set eigenvalues to zero eig[0] = 0. eig[1] = 0. eig[2] = 0. vec[0] = (1, 0, 0) vec[1] = (0, 1, 0) vec[2] = (0, 0, 1) else: #precondition the matrix to avoid floating-point overflow scalem = 1 / scale a00 = tensor[0, 0] * scalem a11 = tensor[1, 1] * scalem a22 = tensor[2, 2] * scalem a01 = tensor[0, 1] * scalem a02 = tensor[0, 2] * scalem a12 = tensor[1, 2] * scalem q = (a00 + a11 + a22) / 3 b00 = a00 - q b11 = a11 - q b22 = a22 - q norm = a01**2 + a02**2 + a12**2 if abs(norm) > normtol: p = ((b00**2 + b11**2 + b22**2 + 2 * norm) / 6)**0.5 c00 = b11 * b22 - a12 * a12 c01 = a01 * b22 - a12 * a02 c02 = a01 * a12 - b11 * a02 half_det = (b00 * c00 - a01 * c01 + a02 * c02) / (p * p * p * 2) if is_real[0] == True: #for real data, half_det is between -1 and 1, to avoid possible rounding error, clamp it, just to make sure half_det = min(max(half_det.real, -1), 1) phi = np.arccos(half_det) / 3. #this number is closest to 2*np.pi/3 in float or double twoThirdsPi = NFDTYPE(2.09439510239319549) eig0 = np.cos(phi + twoThirdsPi) * 2 eig2 = np.cos(phi) * 2 eig1 = -(eig0 + eig2) #eigenvalues sorted by increasing eig0 = (eig0 * p + q) eig1 = (eig1 * p + q) eig2 = (eig2 * p + q) #now compute the eigenvectors if half_det.real >= 0: _eigvec0(a00, a11, a22, a01, a02, a12, eig2, vec[2], vec[1], vec[0], eig) _eigvec1(a00, a11, a22, a01, a02, a12, vec[2], eig1, vec[1], vec[0], eig) _cross(vec[1], vec[2], vec[0]) else: _eigvec0(a00, a11, a22, a01, a02, a12, eig0, vec[0], vec[1], vec[2], eig) _eigvec1(a00, a11, a22, a01, a02, a12, vec[0], eig1, vec[1], vec[2], eig) _cross(vec[0], vec[1], vec[2]) eig[0] = (eig0 * scale) eig[1] = (eig1 * scale) eig[2] = (eig2 * scale) else: #matrix is diagonal eig[0] = a00 * scale eig[1] = a11 * scale eig[2] = a22 * scale vec[0] = (1, 0, 0) vec[1] = (0, 1, 0) vec[2] = (0, 0, 1) _sort_eigvec(eig, vec, eig, vec)
""" Numba optimized linear algebra functions for 4x4 matrices and 2x2 matrices. """ from __future__ import absolute_import, print_function, division from dtmm.conf import NCDTYPE, NFDTYPE, NUMBA_TARGET, NUMBA_PARALLEL, NUMBA_CACHE, NUMBA_FASTMATH, CDTYPE, FDTYPE from numba import njit, prange, guvectorize, boolean import numpy as np if not NUMBA_PARALLEL: prange = range @njit([NFDTYPE(NFDTYPE[:]), NFDTYPE(NCDTYPE[:])], cache=NUMBA_CACHE, fastmath=NUMBA_FASTMATH) def _vecabs2(v): """Computes vec.(vec.conj)""" out = 0. for i in range(len(v)): out = out + v[i].real**2 + v[i].imag**2 return out @njit([NFDTYPE(NFDTYPE[:]), NCDTYPE(NCDTYPE[:])], cache=NUMBA_CACHE, fastmath=NUMBA_FASTMATH) def _vnorm2(v): """Computes vec.vec""" return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]
F[3, 1] = -evpm * sfst #normalize base vectors for j in range(4): tmp = 0. for i in range(4): tmp += F[i, j].real * F[i, j].real + F[i, j].imag * F[i, j].imag tmp = tmp**0.5 F[0, j] = F[0, j] / tmp F[1, j] = F[1, j] / tmp F[2, j] = F[2, j] / tmp F[3, j] = F[3, j] / tmp @nb.njit([NFDTYPE(NCDTYPE[:])], cache=NUMBA_CACHE) def _power(field): tmp1 = (field[0].real * field[1].real + field[0].imag * field[1].imag) tmp2 = (field[2].real * field[3].real + field[2].imag * field[3].imag) return tmp1 - tmp2 @nb.njit([(NCDTYPE[:], NCDTYPE[:, :], NCDTYPE[:], NCDTYPE[:, :])], cache=NUMBA_CACHE) def _copy_sorted(alpha, fmat, out_alpha, out_fmat): i = 0 j = 1 for k in range(4): p = _power(fmat[:, k]) if p >= 0.: out_alpha[i] = alpha[k]