def intensity(theta, amplitude, width, wavelength): result = np.clip(5 * np.random.randn(), 0, None) # Gaussian noise for d in D_SPACINGS['Si']: assert wavelength < 2 * d, \ "wavelength would result in illegal arg to arcsin" try: center = np.arcsin(wavelength / (2 * d)) except Exception: print("DEAD"); center = 0 result += voigt(theta, amplitude, center, width) result += voigt(-theta, amplitude, center, width) return result
def dips(x, c0, wavelength, a1, sigma): sign = -1 # x comes from hardware in [theta or two-theta] degrees x = np.deg2rad(x / factor - offset) # radians assert np.all(wavelength < 2 * D), \ "wavelength would result in illegal arg to arcsin" centers = np.arcsin(wavelength / (2 * D)) # just look at one center for now c1 = centers[0] result = ( voigt(x=x, amplitude=sign * a1, center=c0 - c1, sigma=sigma) + voigt(x=x, amplitude=sign * a1, center=c0 + c1, sigma=sigma)) return result
def blurred_alpha(x, nK=1e-7, L=1e7, p1_stat_weight=(4 / 6) * 0.7, p1_center=766.504333, p1_delta_f_C=3.19e9, p2_stat_weight=0.35, p2_center=769.913219, p2_delta_f_C=3.04e9): # units converted from m to nm e = 1.6e-19 me = 9.1e-31 epsilon0 = 8.85e-39 c = 3e17 f0 = (e**2) / (4 * epsilon0 * me * (c**2)) T = 3000 kb = 1.38e-5 K_MW = 39.1 NA = 6.022E23 mK = (K_MW / 1000) / NA # mK = 39*1.67e-27 #TODO: convert to array math p1_delta_wl_D = 2 * np.sqrt(2 * np.log(2) * kb * T / mK) * (p1_center / c) p1_delta_wl_C = ((p1_center**2) / c) * p1_delta_f_C p1_prefactor = p1_stat_weight * f0 * p1_center**2 p2_delta_wl_D = 2 * np.sqrt(2 * np.log(2) * kb * T / mK) * (p2_center / c) p2_delta_wl_C = ((p2_center**2) / c) * p2_delta_f_C p2_prefactor = p2_stat_weight * f0 * p2_center**2 kappa = p1_prefactor * voigt( x, 1, p1_center, p1_delta_wl_D, p1_delta_wl_C) + p2_prefactor * voigt( x, 1, p2_center, p2_delta_wl_D, p2_delta_wl_C) y = 1 - np.exp(-nK * L * kappa) # assert all(np.diff(x) == np.diff(x)[0]) #Assuming all interpolated data at 0.026 y = gaussian_filter1d(y, 1) return y
def conv_lorentzian_pvoigt(left, right, params, **kwargs): """Convolution between a Lorentzian and a pseudo-Voigt profile. .. math:: \\begin{aligned} & a_L \\mathcal{L}_{\\sigma_L, center_L} \\otimes a_V . p\\mathcal{V}_{\\sigma, center, fraction} = &\\quad a_L a_V \\left[ (1 - fraction) \\mathcal{V}_{\\sigma_g, \\sigma, center + center_L} + fraction \\mathcal{L}_{\\sigma + \\sigma_L, center + center_L} \\right] \\end{aligned} where :math:`p\\mathcal{V}` is the pseudo-Voigt, :math:`\\mathcal{V}` is a Voigt profile, :math:`\\sigma_g = \\frac{\\sigma}{\\sqrt{(2 log(2))}}` and :math:`\\mathcal{L}` is a Lorentzian. """ # set left to lorentzian component if not so if left.func.__name__ == "pvoigt": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] rsigma = rp["sigma_%i" % qId] sigma_v = rsigma / np.sqrt(2 * np.log(2)) frac = rp["fraction_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 if "sigma" in lglob else lp["sigma_%i" % qId] ) out.append( frac * voigt(x, amplitude, center, sigma_v, lsigma) + (1 - frac) * lorentzian(x, amplitude, center, lsigma + rsigma) ) return np.array(out)
def conv_rotations_pvoigt(left, right, params, **kwargs): """Convolution between the rotation model and a pseudo-Voigt profile.""" # set left to rotations component if not so if left.func.__name__ == "pvoigt": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] frac = rp["fraction_%i" % qId] lsigma = lp["sigma"] if "sigma" in lglob else lp["sigma_%i" % qId] rsigma = rp["sigma_%i" % qId] sigma_v = rsigma / np.sqrt(2 * np.log(2)) bondDist = lp["bondDist"] eisf = spherical_jn(0, bondDist * qVal) ** 2 eisf *= pvoigt(x, amplitude, center, rsigma, frac) qisf = np.sum( [ spherical_jn(i, bondDist * qVal) ** 2 * (2 * i + 1) * ( frac * voigt( x, amplitude, center, sigma_v, i * (i + 1) * lsigma ) * (1 - frac) * lorentzian( amplitude, center, rsigma + i * (i + 1) * lsigma ) ) for i in range(1, 5) ], axis=0, ) out.append(eisf + qisf) return np.array(out)
def vibronic_ls(x, s, sigma, gamma, e_vib, kt=0, n_max=None, m_max=None): """ Produce a vibronic (Frank-Condom) lineshape. The vibronic transition amplitude computed relative to 0 (ie: relative to the electronic transition energy). Lines are broadened using a voigt profile. Parameters ---------- x : np.ndarray Energy values. x==0 is the 0->0 line (no vibrational quanta change) s : float Huang-Rhys parameter S e_vib : float Energy of a vibrational quanta sigma : float Width (1/e^2) of gaussian component gamma : float Width of Lorententzian component kt : float Thermal energy. If >0, will compute transitions from vibrationally excited states. Default 0. n_max : int Largest vibrational number in final manifold. If not supplied, a guess is provided, but may not be adequate. m_max : int Largest vibrational number in orginal manifold. If not supplied, a guess is provided, but may not be adequate. """ #determine n, m, values if m_max is None: m_max = 0 if kt == 0 else int(kt / e_vib * 10) # found that factor with my thumb if n_max is None: n_max = m_max + int(10 * s) n = np.arange(n_max + 1) m = np.arange(m_max + 1) # compute boltzmann factors #boltz_f = np.exp(-m*e_vib/kt) if kt>0 else [1] #boltz_f /= np.sum(boltz_f) # FC factors #fcf = fc_factor(m, n, s) #fcf *= boltz_f[:,np.newaxis] fcf = vibronic_intensity(m, n, s, e_vib, kt) n, m = np.meshgrid(n, m) dvib = n - m y = np.zeros_like(x) for d, f in zip(dvib.flatten(), fcf.flatten()): y += voigt(x, f, d * e_vib, sigma, gamma) return y
def peaks(x, c0, wavelength, a1, a2, sigma): # x comes from hardware in [theta or two-theta] degrees x = np.deg2rad(x / factor - offset) # radians assert np.all(wavelength < 2 * D), \ "wavelength would result in illegal arg to arcsin" cs = np.arcsin(wavelength / (2 * D)) c1 = cs[0] c2 = cs[1] #c3 = cs[2] # first peak result = ( voigt(x=x, amplitude=sign * a1, center=c0 - c1, sigma=sigma) + voigt(x=x, amplitude=sign * a1, center=c0 + c1, sigma=sigma)) # second peak result += ( voigt(x=x, amplitude=sign * a2, center=c0 - c2, sigma=sigma) + voigt(x=x, amplitude=sign * a2, center=c0 + c2, sigma=sigma)) # third peak #result += (voigt(x=x, amplitude=sign*a3, center=c0 - c3, sigma=sigma) + #voigt(x=x, amplitude=sign*a3, center=c0 + c3, sigma=sigma)) return result
def conv_gaussian_rotations(left, right, params, **kwargs): """Convolution of a Gaussian and a liquid rotations model.""" # set left to Gaussian component if not so if left.func.__name__ == "rotations": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 if "sigma" in lglob else lp["sigma_%i" % qId] ) bondDist = rp["bondDist"] rsigma = rp["sigma"] if "sigma" in rglob else lp["sigma_%i" % qId] eisf = spherical_jn(0, bondDist * qVal) ** 2 eisf *= gaussian(x, amplitude, center, rsigma) qisf = np.sum( [ spherical_jn(i, bondDist * qVal) ** 2 * (2 * i + 1) * voigt(x, amplitude, center, lsigma, i * (i + 1) * rsigma) for i in range(1, 5) ], axis=0, ) out.append(eisf + qisf) return np.array(out)
def conv_gaussian_lorentzian(left, right, params, **kwargs): """Convolution of a Gaussian and a Lorentzian. Results in a Voigt profile as defined in lineshapes. """ # set left to Gaussian component if not so if left.func.__name__ == "lorentzian": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] sigma = ( lp["sigma"] * qVal ** 2 if "sigma" in lglob else lp["sigma_%i" % qId] ) gamma = ( rp["sigma"] * qVal ** 2 if "sigma" in rglob else lp["sigma_%i" % qId] ) out.append(voigt(x, amplitude, center, sigma, gamma)) return np.array(out)
def conv_jumpdiff_pvoigt(left, right, params, **kwargs): """Convolution between the jump diffusion model and a pseudo-Voigt profile. """ # set left to jump_diff component if not so if left.func.__name__ == "pvoigt": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] frac = rp["fraction_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 / (1 + lp["sigma"] * qVal ** 2 * lp["tau"]) if "sigma" in lglob else lp["sigma_%i" % qId] ) rsigma = rp["sigma_%i" % qId] sigma_v = rsigma / np.sqrt(2 * np.log(2)) out.append( frac * voigt(x, amplitude, center, sigma_v, lsigma) + (1 - frac) * lorentzian(x, amplitude, center, lsigma + rsigma) ) return np.array(out)
def bloch_reph_diag(x, amp, x0, s, g): """ Rephasing bloch diagonal lineshape Parameters ---------- x : array-like Independant axis (energy/frequency) amp : float Amplitude x0 : float Peak position s : float Inhomogeneous linewidth sigma g : float Homogeneous linewidth gamma Returns ------- lineshape : array-like Complex lineshape amplitude """ return np.sqrt(2 * np.pi) / g * voigt(x, amp, x0, s, g)
def peakfunc(x, amplitude, sigma, x0, slope, intercept): # amplitude is *not* amplitude!!! needs to be rescaled by sigma!!!! amplitude = amplitude * sigma * np.sqrt(2 * np.pi) result = voigt(x=x, amplitude=amplitude, center=x0, sigma=sigma) result += slope * x + intercept return result
def dips(x, c1, a1, sigma): sign = -1 result = voigt(x=x, amplitude=sign * a1, center=c1, sigma=sigma) return result
def conv_gaussian_pvoigt(left, right, params, **kwargs): """Convolution between a Gaussian and a pseudo-Voigt profile. .. math:: \\begin{aligned} & a_L G_{\\sigma_G, center_G} \\otimes a_V . \\mathcal{pV}_{\\sigma, center, fraction} = & \\quad a_G a_V \\left[fraction \\mathcal{V}_{\\sigma_G, \\sigma, center + center_G} + (1 - fraction) G_{\\sigma_g + \\sigma_G, center + center_G} \\right] \\end{aligned} where :math:`\\mathcal{pV}` is the pseudo-Voigt, :math:`\\mathcal{V}` is a Voigt profile, and :math:`\\sigma_g = \\frac{\\sigma}{\\sqrt{(2 log(2))}}`. """ # set left to gaussian component if not so if left.func.__name__ == "pvoigt": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] rsigma = rp["sigma_%i" % qId] frac = rp["fraction_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 if "sigma" in lglob else lp["sigma_%i" % qId] ) sigma_g = rsigma / np.sqrt(2 * np.log(2)) convGauss = amplitude / np.sqrt( 2 * np.pi * (sigma_g ** 2 + lsigma ** 2) ) convGauss *= np.exp( -((x - center) ** 2) / (2 * sigma_g ** 2 + lsigma ** 2) ) out.append( frac * convGauss + (1 - frac) * voigt(x, amplitude, center, lsigma, rsigma) ) return np.array(out)