def __call__(self, domain, field): """ :param object domain: A domain :param object field: Current field :return: Field after modification by Gaussian filter :rtype: Object """ # Convert field to spectral domain: self.field = fft(field) delta_nu = domain.nu - domain.centre_nu - self.offset_nu factor = power(delta_nu / self.width_nu, (2 * self.m)) # Frequency values are in order, inverse shift to put in fft order: self.shape = exp(-0.5 * ifftshift(factor)) if domain.channels > 1: # Filter is applied only to one channel: self.field[self.channel] *= self.shape else: self.field *= self.shape # convert field back to temporal domain: if self.type is "reflected": return ifft(self.field) else: return field - ifft(self.field)
def transfer_function(self, nu, centre_nu): """ :param Dvector nu: Spectral domain array. :param double centre_nu: Centre frequency. :return: Array of values. :rtype: Dvector Generate an array representing the filter power transfer function. """ if len(nu) < 8: raise OutOfRangeError( "Require spectral array with at least 8 values") delta_nu = nu - centre_nu - self.offset_nu factor = power(delta_nu / self.width_nu, (2 * self.m)) self.shape = exp(-0.5 * factor) return abs(self.shape)**2
def __init__(self, name="filter", width_nu=0.1, offset_nu=0.0, m=1, channel=0, using_fwhm=False, type_filt="reflected"): if not (1e-6 < width_nu < 1e3): raise OutOfRangeError( "width_nu is out of range. Must be in (1e-6, 1e3)") if not (-200.0 < offset_nu < 200.0): raise OutOfRangeError( "offset_nu is out of range. Must be in (-200.0, 200.0)") if not (0 < m < 50): raise OutOfRangeError("m is out of range. Must be in (0, 50)") if not (0 <= channel < 2): raise OutOfRangeError("channel is out of range. Must be in [0, 2)") if int(m) != m: raise NotIntegerError("m must be an integer") if int(channel) != channel: raise NotIntegerError("channel must be an integer") self.name = name self.width_nu = width_nu self.offset_nu = offset_nu self.m = m self.channel = channel self.fwhm_nu = None self.type = type_filt # For a FWHM filter width, store then convert to a HWIeM filter width: if using_fwhm: self.fwhm_nu = width_nu # store fwhm filter width self.width_nu *= 0.5 / power(log(2.0), 1.0 / (2 * m)) self.shape = None self.field = None
def generate(self, t): """ :param Dvector t: Temporal domain array :return: Array of complex values. *Unit:* :math:`\sqrt{W}` :rtype: Cvector Generate an array of complex values representing a Gaussian pulse. """ if len(t) < 8: raise OutOfRangeError( "Require temporal array with at least 8 values") # Assume t[0] = t_0 and t[-1] = t_0 + t_range - dt, # with dt = t[1] - t[0] t_range = t[-1] - t[0] + (t[1] - t[0]) t_normalised = (t - self.position * t_range) / self.width time = power(t_normalised, (2 * self.m)) phase = self.initial_phase phase -= 2.0 * pi * self.offset_nu * t + 0.5 * self.C * time return sqrt(self.peak_power) * exp(-0.5 * time + 1j * phase)
def __call__(self, domain, field): """ :param object domain: A domain :param object field: Current field :return: Field after modification by Gaussian :rtype: Object """ self.field = field t_normalised = \ (domain.t - self.position * domain.window_t) / self.width time = power(t_normalised, (2 * self.m)) phase = self.initial_phase phase -= 2.0 * pi * self.offset_nu * domain.t + 0.5 * self.C * time magnitude = sqrt(self.peak_power) * exp(-0.5 * time) if domain.channels > 1: self.field[self.channel] += magnitude * exp(1j * phase) else: self.field += magnitude * exp(1j * phase) return self.field
def fib_closed(num): return (power(a, num) - power(b, num)) / (a - b)
def calculate_fwhm(self): """ Convert a HWIeM width to a FWHM width. """ if self.fwhm_nu is not None: return self.fwhm_nu else: return self.width_nu * 2.0 * power(log(2.0), 1.0 / (2 * self.m))
def bin_spinode(L,x=None,T=None): """ Calculates a binary spinodal at either a fixed composition or temperature. If x is given, the corresponding T_spinodal is returned. If T is given, the two corresponding x_spinodal are returned. """ from numpy.lib.scimath import power if x != None: T_sp = 2*x*(1-x)*(L[0]+3*L[1]*(1-2.*x))/BoltzConst return T_sp elif T != None: # Coefficients of cubic equation a*x**3+b*x**2+c*x+d a = 6.*L[1] b = -(L[0]+9.*L[1]) c = L[0]+3.*L[1] d = -T*BoltzConst/2. discrim = 18.*a*b*c*d-4.*b**3*d+b**2*c**2-4*a*c**3-27.*a**2*d**2 if discrim >= 0.: temp = 2.*b**3-9.*a*b*c+27.*a**2*d x1 = (power(0.5*(temp + power(-27.*a**2*discrim,1./2.)),1./3.) + power(0.5*(temp - power(-27.*a**2*discrim,1./2.)),1./3.) + b)/(-3.*a) x2 = (power(0.5*(temp + power(-27.*a**2*discrim,1./2.)),1./3.) *(1.+np.sqrt(3)*j) + power(0.5*(temp - power(-27.*a**2*discrim,1./2.)),1./3.) *(1.-np.sqrt(3)*j) - 2.*b)/(6.*a) x3 = (power(0.5*(temp + power(-27.*a**2*discrim,1./2.)),1./3.) *(1.-np.sqrt(3)*j) + power(0.5*(temp - power(-27.*a**2*discrim,1./2.)),1./3.) *(1.+np.sqrt(3)*j) - 2.*b)/(6.*a) x_sp = sorted([x1,x2,x3]) return x_sp[0],x_sp[1] else: # There exists 1 real root and 2 complex roots print "There exists only 1 real root!" return
def __init__(self, name="gaussian", position=0.0, width=10.0, peak_power=1e-3, offset_nu=0.0, m=1, C=0.0, initial_phase=0.0, channel=0, using_fwhm=False): if not (-0.5 <= position <= 0.5): raise OutOfRangeError( "position is out of range. Must be in [-0.5, 0.5]") if not (1e-3 < width < 1e3): raise OutOfRangeError( "width is out of range. Must be in (1e-3, 1e3)") if not (0.0 <= peak_power < 1e9): raise OutOfRangeError( "peak_power is out of range. Must be in [0.0, 1e9)") if not (-300.0 < offset_nu < 300.0): raise OutOfRangeError( "offset_nu is out of range. Must be in (-300.0, 300.0)") if not (0 < m < 50): raise OutOfRangeError("m is out of range. Must be in (0, 50)") if not (-1e3 < C < 1e3): raise OutOfRangeError("C is out of range. Must be in (-1e3, 1e3)") if not (0.0 <= initial_phase < 2.0 * pi): raise OutOfRangeError( "initial_phase is out of range. Must be in [0.0, 2.0 * pi)") if not (0 <= channel < 2): raise OutOfRangeError("channel is out of range. Must be in [0, 2)") if int(m) != m: raise NotIntegerError("m must be an integer") if int(channel) != channel: raise NotIntegerError("channel must be an integer") self.name = name self.position = position self.width = width # ps self.peak_power = peak_power # W self.offset_nu = offset_nu # THz self.m = m self.C = C # rad self.initial_phase = initial_phase # rad self.channel = channel self.fwhm = None # For a FWHM pulse width, store then convert to a HWIeM pulse width: if using_fwhm: self.fwhm = width # store fwhm pulse width self.width *= 0.5 / power(log(2.0), 1.0 / (2 * m)) self.field = None
def getDist(point1, point2): sumVal = 0 for i in xrange(len(point1)): sumVal += power(point1[i]+point2[i],2) return sqrt(sumVal)
def calc_roots_of_low_order_polynomial(C): """ Calculates the (complex) roots of polynomials up to order 3 in parallel. The coefficients of the polynomials are in the first dimension of C and repeated in the following dimensions, one for each polynomial to determine the roots of. The coefficients are input for low to high order in each column. In other words, the polynomial is: ``np.sum(C * (x**range(C.size))) == 0`` :param C: The coefficients of the polynomial, per polynomial. :return: The zeros in the complex plane, per polynomial. """ nb_terms = C.shape[0] output_shape = np.array(C.shape) output_shape[0] -= 1 # A few helper functions def sign(arr): # signum without the zero return 2 * (arr >= 0) - 1 def is_significant(arr): return np.abs(arr) > np.sqrt(np.finfo(arr.dtype).eps) def add_roots(coeffs): """ Checks if this is a lower-order polynomial in disguise and adds zero roots to match the order of the array :param coeffs: The polynomial coefficient array :return: A, nb_roots_added The non-degenerate polynomial coefficient array, A, and the number of roots added """ # Although the coefficients are integers, the calculations may be real and complex. coeffs = np.array(coeffs, dtype=np.complex128) coeffs = coeffs[..., np.newaxis] # add a singleton dimension to avoid problems with vectors roots_added = np.zeros(coeffs[0].shape, dtype=np.uint8) for outer_dim_idx in range(coeffs.shape[0]): lower_order = np.where(coeffs[-1] == 0) for dim_idx in np.arange(coeffs.shape[0]-1, 0, -1): coeffs[dim_idx][lower_order] = coeffs[dim_idx-1][lower_order] coeffs[0][lower_order] = 0 roots_added[lower_order] += 1 coeffs[-1][lower_order] = 1 # all zeros return coeffs[..., 0], roots_added[..., 0] def remove_roots(roots, roots_added): """ Removes dummy roots at ``x == 0`` and replaces them with nan at the end of the vector of roots. The roots are sorted with np.sort (real first, imaginary second). :param roots: The array of all calculated roots. :param roots_added: The number of dummy roots added to the problem. :return: The array with the dummy roots placed at the end and replaced by nan. """ roots = roots[..., np.newaxis] # add a singleton dimension to avoid problems with vectors roots_added = roots_added[..., np.newaxis] # add a singleton dimension to avoid problems with vectors for dim_idx in np.arange(roots.shape[0]-1, -1, -1): is_zero = np.bitwise_not(is_significant(roots[dim_idx])) remove_zero = np.where(is_zero & (roots_added > 0)) roots[dim_idx][remove_zero] = np.nan roots_added[remove_zero] -= 1 roots = np.sort(roots, axis=0) return roots[..., 0] if nb_terms < 2: X = np.empty((0, *C[1:]), dtype=C.dtype) elif nb_terms == 2: # linear # C[0] + C[1]*X == 0 C, nb_roots_added = add_roots(C) X = -C[np.newaxis, 0] / C[np.newaxis, 1] X = remove_roots(X, nb_roots_added) elif nb_terms == 3: # quadratic # C[0] + C[1]*X + C[2]*X**2 == 0 C, nb_roots_added = add_roots(C) d = C[1] ** 2 - 4.0 * C[2] * C[0] sqrt_d = sm.sqrt(d) q = -0.5 * (C[1] + sign((np.conj(C[1]) * sqrt_d).real) * sqrt_d) X = np.array((q / C[2], C[0] / (q + (1 - is_significant(C[0])) * (1 - is_significant(q))))) X = remove_roots(X, nb_roots_added) elif nb_terms == 4: # cubic C, nb_roots_added = add_roots(C) a = C[2] / C[3] / 3 b = C[1] / C[3] c = C[0] / C[3] Q = a ** 2 - b / 3 R = a ** 3 + (- a * b + c) / 2 del b, c S2 = R ** 2 - Q ** 3 complex_root = True #TODO: fix numerical issues with real roots. is_significant(R.imag) | is_significant(Q.imag) | (S2 >= 0) not_around_origin = is_significant(Q) # avoiding division by zero in case the roots are centered around zero RQm32 = sm.power(R, 1/3) / (not_around_origin * sm.sqrt(Q) + (1 - not_around_origin)) AB_all_real_roots = -sm.sqrt(Q) * (RQm32 + 1j * sm.sqrt(1.0 - RQm32**2)) S = sm.sqrt(S2) # S**2 = R**2 - Q**3 => Q**3 == R**2 - S**2 = (R-S)*(R+S) A_complex_root = -sm.power(R + sign(np.real(np.conj(R) * S)) * S, 1/3) # Combine the different calculations for A A = complex_root * A_complex_root + (1 - complex_root) * AB_all_real_roots # choose sign of sqrt so that real(conj(R) * sqrt(R**2 - Q**3)) >= 0 A_significant = is_significant(A) # if A insignificant, then R + np.sign(np.real(np.conj(R) * S)) * S == 0 # and can be divided out of Q^3 = R^2 - S^2 = (R-S)*(R+S) B_complex_roots = Q / (A + (1 - A_significant)) # avoiding division by zero B_complex_roots_origin = - sm.power(R - np.sign(np.real(np.conj(R) * S)) * S, 1/3) # Combine the different calculations for B B = complex_root * (A_significant * B_complex_roots + (1 - A_significant) * B_complex_roots_origin) \ + (1 - complex_root) * (-AB_all_real_roots) complex_triangle = utils.to_dim(np.exp(2j * const.pi * np.array([-1, 0, 1]) / 3), output_shape.size, 0) X = A[np.newaxis, ...] * complex_triangle + B[np.newaxis, ...] * np.conj(complex_triangle) X -= a[np.newaxis, ...] X = remove_roots(X, nb_roots_added) else: message = 'Orders above 3 not implemented!' log.critical(message) raise Exception(message) return X
def distEclud(vecA, vecB): return sqrt(sum(power(vecA - vecB, 2)))