def moment(self, n, alpha, beta): r""" n-th (non central) moment of the Beta distribution .. math:: E = \frac{\Gamma \left( n + \alpha\right )}{\beta^{n}\Gamma \left ( \alpha \right )} Parameters ---------- n : integer or numpy array of integers The ordinal of the moment to calculate alpha : numpy array or scalar One shape parameter for the Beta distribution beta : numpy array or scalar Another scale parameter for the Beta distribution Returns ------- moment : scalar or numpy array The moment(s) of the Beta distribution Examples -------- >>> from surpyval import Beta >>> Beta.moment(2, 3, 4) 0.75 """ return gamma_func(n + alpha) / (beta**n * gamma_func(alpha))
def _weibull_variance(shape, scale): r""" given $\lambda$ (`scale`) and $k$ (`shape`), the variance is computed as: \operatorname{var}(X)=\lambda^{2}\left[\Gamma\left(1+\frac{2}{k}\right)-\left(\Gamma\left(1+\frac{1}{k}\right)\right)^{2}\right] """ return scale**2 * (gamma_func(1 + 2 / shape) - gamma_func(1 + 1 / shape)**2)
def analyticgetMarginalLikelihood(self): left = gamma_func(self.vn/2.)/gamma_func(self.v0/2.) middleLeft = self.k0/self.kn middleRightTop = pow(self.v0*self.sigma0,self.v0/2.) middleRightBottom = pow(self.vn*self.sigman,self.vn/2.) middle = np.sqrt(middleLeft) * (middleRightTop/middleRightBottom) right = 1./pow(pi,self.n/2.) return left*middle*right
def f_infty(th, beta, xi): """ Function to be zeroed """ k = 2.0 / xi - 2 C = (k + 2 * (1 - beta)) / (k + 2) I = np.sqrt(np.pi) * gamma_func(0.5 * (k + 1)) / (4 * gamma_func(0.5 * k + 2)) D = np.pi + 2 * beta * I return th - C * np.tan(th) - D
def _finf(th, beta, xi): """Function that gives f(theta) = 0 when theta = theta_infty Version for hemispheric flow with anisotropy xi """ k = 2./xi-2 C = (k+2*(1-beta))/(k+2) I = np.sqrt(np.pi)*gamma_func(0.5*(k+1))/(4*gamma_func(0.5*k+2)) D = np.pi + 2*beta*I return th - C*np.tan(th) - D
def _alpha_func(alpha, lev, h=1., max_level=1.): if h > machine_eps(0): g1 = gamma_func(max_level - lev + h) g2 = gamma_func(max_level - lev + 1) g3 = gamma_func(h) return alpha * g1 / (g2 * g3) elif hasattr(lev, '__iter__'): return alpha * np.array([lev_ == max_level for lev_ in lev], dtype=np.float) else: return alpha * np.float(lev == max_level)
def t_pdf(x, mu, sig, nu): """ Univariate t-distribution. Input: X - input data. mu - mean of the distribution. sig - sacle of the distribution. nu - degrees of freedom. Output: px - output data. """ px = gamma_func((nu + 1) / 2) / \ (np.sqrt(nu * np.pi * sig) * gamma_func(nu / 2)) px = px * np.float_power(1 + (x - mu) ** 2 / (nu * sig), (-nu - 1) / 2) return px
def moment(self, n, alpha, beta): r""" n-th moment of the Weibull distribution .. math:: M(n) = \alpha^n \Gamma \left ( 1 + \frac{n}{\beta} \right ) Parameters ---------- n : integer or numpy array of integers The ordinal of the moment to calculate alpha : numpy array or scalar scale parameter for the Weibull distribution beta : numpy array or scalar shape parameter for the Weibull distribution Returns ------- mean : scalar or numpy array The moment(s) of the Weibull distribution Examples -------- >>> from surpyval import Weibull >>> Weibull.moment(2, 3, 4) 7.976042329074821 """ return alpha**n * gamma_func(1 + n/beta)
def shotnoise_PDF_laplaceA(phi_rg, gamma_val, phi_rms): """ Computes the PDF for a shotnoise process with Laplace distributed Amplitudes A ~ Laplace(0, a) See O.E. Garcia and A. Theodorsen, https://arxiv.org/abs/1702.00105 phi_rms PDF(Phi) = sqrt(gamma / pi) / Gamma(gamma / 2) * (sqrt(gamma) |Phi| / Phi_rms) ^ ((gamma - 1) / 2) * Kv((gamma-1) / 2, sqrt(gamma) |Phi| / Phi_rms) Input: ====== phi_rg...... ndarray, float: Domain of the PDF gamma_val... float, intermittency parameter phi_rms..... float, root mean squre value of the underlying sample Returns: ======= res......... ndarray, float: The PDF on the domain """ from scipy.special import gamma as gamma_func from scipy.special import kv t1 = np.sqrt(gamma_val / np.pi) / gamma_func(0.5 * gamma_val) t2 = (0.5 * np.sqrt(gamma_val) * np.abs(phi_rg) / phi_rms)**(0.5 * (gamma_val - 1.)) t3 = kv(0.5 * (gamma_val - 1.), np.sqrt(gamma_val) * np.abs(phi_rg) / phi_rms) return (t1 * t2 * t3)
def density(self, coords, rad, p): """ TODO: This density is not actually flexible but restricted to the concentration marginal above. Change that? Parameters ---------- coords : np.ndarray Coordinates in either a shape of ``(n_samples, n_rvs)`` or ``(n_rvs, n_samples)``. rad : np.ndarray Array of shape ``(n_samples, )`` containing radii. p : np.ndarray Array of shape ``(n_samples, )`` containing p-values. Returns ------- np.ndarray Array of shape ``(n_samples, )`` with density function values. """ area = 2 * np.pi**(self.n_rvs / 2) / gamma_func(self.n_rvs / 2) if coords.shape[0] == self.n_rvs: coord_rad = np.linalg.norm(coords, axis=0, ord=2) else: print( "Warning in CSDistribution.density: Unconventional coordinate array shape." " Check the dimensions of your array, given was: ", coords.shape, "\n Assuming you use shape (number samples, dimension of each sample)" ) coord_rad = np.linalg.norm(coords, axis=1, ord=2) return self.marginal.density(coord_rad, rad, p) / (coord_rad**(self.n_rvs - 1) * area)
def upper_gamma_ext(a, x): if a > 0: return gammaincc(a, x) * gamma_func(a) elif a == 0: return exp1(x) else: return (upper_gamma_ext(a + 1, x) - np.power(x, a) * np.exp(-x)) / a
def volume_gamma(d, d0, N, nu=-0.8): '''Returns the gamma distribution weights corresponding to the given diameters using the given parameters. All quantities should be in MKS.''' rat = d / d0 return ((N * (3 *(nu + 1) ** (nu + 1)) / (d0 * gamma_func(nu + 1))) * (rat**(3*nu + 2) * exp(-(nu+1) * rat**3)))
def mean(data): """" Вычисляет математическое ожидание по указанному закону. Parameters ---------- data : obj Информация о виде распределения. data.distrib : {'rav', 'weib', 'beta', 'gamma'} Название закона распределения. data.param : string, optional Значения параметров распределения. Returns ------- float Численное значение математического ожидания. Raises ------ KeyError Когда в параметре data нет требуемых полей со значениями параметров указанного распределения. Exception Когда указано неверное\неподдерживаемое название распределения. """ distrib = data['distrib'] # Равномерное распределение if distrib == 'rav': try: return (float(data['a']) + float(data['b'])) / 2 except KeyError: print('Параметры равномерного распределения указаны неверно') # Распределение Вейбулла elif distrib == 'weib': try: return gamma_func(1 + 1 / float(data['k'])) except KeyError: print('Параметры распределения Вейбулла указаны неверно') # Гамма-распределение elif distrib == 'gamma': try: return float(data['k']) * float(data['theta']) except KeyError: print('Параметры Гамма-распределения указаны неверно') # Бета-распределение с переводом интервала из [0; 1] в [a; b] elif distrib == 'beta': try: return float(data['alpha']) * (float(data['a']) + float( data['b'])) / (float(data['alpha']) + float(data['beta'])) except KeyError: print('Параметры бета-распределения указаны неверно') else: raise Exception('Неверно указано распределение')
def scoring_knn(self, scalar=1., base=np.e, k=5, n_per_sample=10): knn = self.knn_distance(k, n_per_sample).T[-1] n, p = self.data.V.shape # inv_scores = (base**(- scalar * knn).T / self.data.R).T inv_scores = (k / n) / (np.pi**((p - 1) / 2) / gamma_func( (p - 1) / 2 + 1) * knn**(p - 1)) / self.data.R return 1 / inv_scores
def constrained_gamma_from_moments(N, qr, d, preferred_slope=10): '''Returns the constrained gamma distribution for the given set of moments. d are the diameters, N is the number concentration, qr the liquid water content, and shape is the gamme shape parameter. All quantities should be in MKS. This distribution relies on the lamba-mu relation of Brandes et al. (2001) to reduce the parameter space to match the number of moments available. Because this process yields a high order polynomial, one of the positive roots must be selected based on a critera--by default the value closes to 10 (mm^-1) is selected, but this can be overridden with a different value or a callable.''' slope = constrained_gamma_slope(N, qr, preferred_slope) shape = constrained_gamma_shape(slope) # If the slope is nan, it means fitting the contrained gamma failed and # we need to replace with with that from an exponential distribution fix_mask = np.isnan(slope) if np.any(fix_mask): import warnings warnings.warn('Replacing some fits with exponential: %d' % (fix_mask.sum())) slope[fix_mask] = exponential_slope(N[fix_mask], qr[fix_mask]) shape[fix_mask] = 0. # For better numerical stability, we don't calculate the intercept # parameter directly. Instead, it's incorporated into a different # parameterized form of the distribution. norm_d = no_units(d * slope) return N * slope * norm_d ** shape * exp(-norm_d) / gamma_func(shape + 1)
def mean(self, alpha, beta): r""" Mean of the Weibull distribution .. math:: E = \alpha \Gamma \left ( 1 + \frac{1}{\beta} \right ) Parameters ---------- alpha : numpy array or scalar scale parameter for the Weibull distribution beta : numpy array or scalar shape parameter for the Weibull distribution Returns ------- mean : scalar or numpy array The mean(s) of the Weibull distribution Examples -------- >>> from surpyval import Weibull >>> Weibull.mean(3, 4) 2.7192074311664314 """ return alpha * gamma_func(1 + 1./beta)
def test_get_dt_for_accurate_interpolation(): s = 0.5 wc = 4 intg = lambda x: osd(x, s, wc) bcf_ref = lambda t: gamma_func(s + 1) * wc**(s+1) * (1 + 1j*wc * t)**(-(s+1)) dt = sp.method_ft.get_dt_for_accurate_interpolation(t_max=40, tol=1e-4, ft_ref=bcf_ref) print(dt)
def _calc_q(x, Ts, ws, alphas, betas): param_terms = alphas * np.log(betas) - np.log( gamma_func(alphas)) + np.log(ws) combined_terms = ((alphas[:, np.newaxis] - 1) * np.log([ x, ] * alphas.shape[0]) - betas[:, np.newaxis] * np.array([ x, ] * alphas.shape[0])) return np.sum(Ts * (param_terms[:, np.newaxis] + combined_terms))
def ELBO(k, a, b): """ implements equation 21.98 in Murphy :param k: the kappa parameter :param a: the a parameter :param b: the b parameter :return: """ return -0.5*np.log(k) + np.log(gamma_func(a)) - a*np.log(b)
def test_calc_abN(): def testing(intg, bcf_ref, tol, tmax): diff_method = method_ft._absDiff a, b, N, dx, dt = sp.method_ft.calc_ab_N_dx_dt(integrand=intg, intgr_tol=tol, intpl_tol=tol, t_max=tmax, ft_ref=bcf_ref, opt_b_only=True, diff_method=diff_method) tau, ft_tau = sp.method_ft.fourier_integral_midpoint(intg, a, b, N) idx = np.where(tau <= tmax) ft_ref_tau = bcf_ref(tau[idx]) rd = diff_method(ft_tau[idx], ft_ref_tau) tau_fine = np.linspace(0, tmax, 1500) ft_ref_n = bcf_ref(tau_fine) ft_intp = sp.tools.ComplexInterpolatedUnivariateSpline(x=tau[idx], y=ft_tau[idx], k=3, noWarning=True) ft_intp_n = ft_intp(tau_fine) d = diff_method(ft_intp_n, ft_ref_n) assert rd < tol assert d < tol assert (np.abs(dx * dt * N - np.pi * 2)) < 1e-15 s = 0.5 wc = 4 intg = lambda x: osd(x, s, wc) bcf_ref = lambda t: gamma_func(s + 1) * wc**(s+1) * (1 + 1j*wc * t)**(-(s+1)) tol = 1e-3 tmax=40 testing(intg, bcf_ref, tol, tmax) s = 0.5 wc = 40 intg = lambda x: osd(x, s, wc) bcf_ref = lambda t: gamma_func(s + 1) * wc ** (s + 1) * (1 + 1j * wc * t) ** (-(s + 1)) tol = 1e-3 tmax = 40 testing(intg, bcf_ref, tol, tmax)
def gamma_pdf(x, alpha, beta): """ Univariate gamma-distribution. Input: X - input data. alpha - parameter of the distribution. beta - parameter of the distribution. Output: px - output data. """ px = np.float_power(beta, alpha) / gamma_func(alpha) px = px * np.exp(-beta * x) * np.float_power(x, alpha - 1) return px
def _density_2d_r(self, r, rho0, r_core, gamma): """ Returns the convergence at radius r after applying _safe_r_division :param r: position [arcsec] :param sigma0: convergence at r=0 :param r_core: core radius [arcsec] :param gamma: logarithmic slope at r -> infinity :return: convergence at r """ sigma0 = self._rho02sigma(rho0, r_core) if gamma == 3: return 2 * r_core**2 * sigma0 / (r**2 + r_core**2) elif gamma == 2: return np.pi * r_core * sigma0 / (r_core**2 + r**2)**0.5 else: x = r / r_core exponent = (1 - gamma) / 2 return sigma0 * np.sqrt(np.pi) * gamma_func( 0.5 * (gamma - 1)) / gamma_func(0.5 * gamma) * (1 + x**2)**exponent
def test_fourier_integral_infinite_boundary(plot=False): s = 0.5 wc = 4 intg = lambda x: osd(x, s, wc) bcf_ref = lambda t: gamma_func(s + 1) * wc**(s+1) * (1 + 1j*wc * t)**(-(s+1)) a,b = sp.method_ft.find_integral_boundary_auto(integrand=intg, tol=1e-12, ref_val=1) errs = [9e-5, 2e-5, 1.3e-6] for i, N in enumerate([2**16, 2**18, 2**20]): tau, bcf_n = sp.method_ft.fourier_integral_midpoint(intg, a, b, N=N) bcf_ref_n = bcf_ref(tau) tau_max = 5 idx = np.where(tau <= tau_max) tau = tau[idx] bcf_n = bcf_n[idx] bcf_ref_n = bcf_ref_n[idx] rd_mp = np.abs(bcf_ref_n-bcf_n)/np.abs(bcf_ref_n) if plot: p, = plt.plot(tau, rd_mp, label="trapz N {}".format(N)) tau, bcf_n = sp.method_ft.fourier_integral_simps(intg, a, b=b, N=N-1) bcf_ref_n = bcf_ref(tau) idx = np.where(tau <= tau_max) tau = tau[idx] bcf_n = bcf_n[idx] bcf_ref_n = bcf_ref_n[idx] rd_sm = np.abs(bcf_ref_n-bcf_n)/np.abs(bcf_ref_n) if plot: plt.plot(tau, rd_sm, label="simps N {}".format(N), color=p.get_color(), ls='--') t_ = 3 x_simps, dx = np.linspace(a,b,N-1, endpoint=True, retstep=True) I = sp_int.simps(intg(x_simps)*np.exp(-1j*x_simps*t_), dx=dx) err = np.abs(I-bcf_ref(t_))/np.abs(bcf_ref(t_)) assert np.max(rd_mp) < errs[i], "np.max(rd_mp) = {} >= {}".format(np.max(rd_mp), errs[i]) assert np.max(rd_sm) < errs[i], "np.max(rd_sm) = {} >= {}".format(np.max(rd_sm), errs[i]) if plot: plt.plot(t_, err, marker='o', color='g') if plot: plt.legend(loc='lower right') plt.grid() plt.yscale('log') plt.show()
def _f(x, gamma): """ Returns the solution of the 2D mass integral defined such that .. math:: m_{\rm{2D}}\left(R\right) = 4 \pi r_{\rm{core}}^3 \rho_0 F\left(\frac{R}{r_{\rm{core}}}, \gamma\right) :param x: dimensionaless radius r/r_core :param gamma: logarithmic slope at r -> infinity :return: a number """ if gamma == 3: return 0.5 * np.log(x**2 + 1) elif gamma == 2: return np.pi / 2 * ((x**2 + 1)**0.5 - 1) else: gamma_func_term = gamma_func(0.5 * (gamma - 1)) / gamma_func(0.5 * gamma) prefactor = np.sqrt(np.pi) * gamma_func_term / (2 * (gamma - 3)) term = (1 - (1 + x**2)**((3 - gamma) / 2)) return prefactor * term
def prob_dist(vals, mean, var): """ Evaluates Gamma pdf with parameters adjusted to give an inputted mean and variance. :param vals: np.array, values to be evaluated :param mean: float, inputted distribution mean :param var: float, inputted distribution variance :return: np.array, same length as vals, Gamma pdf evaulations """ gamma_beta = mean / var gamma_alpha = mean * gamma_beta return gamma_beta**gamma_beta / gamma_func(gamma_alpha) * vals**( gamma_alpha - 1) * np.exp(-gamma_beta * vals)
def by_norm(x, alpha_prior, beta_prior, gamma_prior, delta_prior, x_test): """Bayesian approach to normal distribution. Input: x - training data. alpha_prior - hyperparameter of normal-scaled inverse gamma distribution. beta_prior - hyperparameter of normal-scaled inverse gamma distribution. gamma_prior - hyperparameter of normal-scaled inverse gamma distribution. delta_prior - hyperparameter of normal-scaled inverse gamma distribution. x_test - test data. Output: alpha_post - posterior parameters. beta_post - posterior parameters. gamma_post - posterior parameters. delta_post - posterior parameters. x_prediction - predictive distribution. """ I = x.size x_sum = np.sum(x) # Compute normal inverse gamma posterior over normal parameters alpha_post = alpha_prior + I / 2 beta_post = np.sum(x ** 2) / 2 + beta_prior + gamma_prior * (delta_prior ** 2) / 2 - \ (gamma_prior * delta_prior + x_sum) ** 2 / (2 * (gamma_prior + I)) gamma_post = gamma_prior + I delta_post = (gamma_prior * delta_prior + x_sum) / (gamma_prior + I) # Compute intermediate parameters alpha_int = alpha_post + 1 / 2 beta_int = x_test ** 2 / 2 + beta_post + gamma_post * delta_post ** 2 / 2 - \ (gamma_post * delta_post + x_test) ** 2 / (2 * (gamma_post + 1)) gamma_int = gamma_post + 1 # Predict values for x_test x_prediction_num = np.sqrt( gamma_post) * np.float_power(beta_post, alpha_post) * gamma_func(alpha_int) x_prediction_den = np.sqrt(2 * np.pi * gamma_int) * \ np.float_power(beta_int, alpha_int) * gamma_func(alpha_post) x_prediction = x_prediction_num / x_prediction_den return (alpha_post, beta_post, gamma_post, delta_post, x_prediction)
def test_get_N_a_b_for_accurate_fourier_integral_b_only(): s = 0.5 wc = 4 intg = lambda x: osd(x, s, wc) bcf_ref = lambda t: gamma_func(s + 1) * wc**(s+1) * (1 + 1j*wc * t)**(-(s+1)) a, b = sp.method_ft.find_integral_boundary_auto(integrand=intg, tol=1e-2, ref_val=1) a = 0 N, a, b = sp.method_ft.get_N_a_b_for_accurate_fourier_integral(intg, t_max=15, tol=1e-5, ft_ref=bcf_ref, opt_b_only=True) print(N,a,b)
def gamma_sn(x, params): """ Gamma distribution for shot-noise process in terms of shape and scale parameter. shape: gamma = <Phi>^2/Phi_rms^2 scale: Phi_rms^2 / <Phi> PDF(Phi) = 1 / (scale * Gamma(shape)) * (x/scale) ** (shape - 1) * exp(-x / scale) """ shape, scale = params #print 'gamma_ss: shape = %f, scale = %f' % (shape, scale) retval = 1. / (gamma_func(shape) * scale) *\ (x / scale) ** (shape - 1.) *\ np.exp(-x / scale) return retval
def pdf_gamma_mv(vals, mean, var): """ Evaluates Gamma pdf with parameters adjusted to give an inputted mean and variance. :param vals: np.array, values to be evaluated :param mean: float, inputted distribution mean :param var: float, inputted distribution variance :return: np.array, same length as vals, Gamma pdf evaulations """ gamma_beta = mean / var gamma_alpha = mean * gamma_beta if any(np.atleast_1d(vals) <= 0): raise ValueError("Gamma pdf takes only positive values") return gamma_beta**gamma_beta / gamma_func(gamma_alpha) * vals**( gamma_alpha - 1) * np.exp(-gamma_beta * vals)
def knn_euclidean_distance_to_postpred(self, k=10, **kwargs): knn = np.array(list(map(np.sort, self.euclidean_distance)))[:, k] try: n, p = self.data.VW.shape except AttributeError: try: n, p = self.data.V.shape except AttributeError: try: n, p = self.data.W.shape except AttributeError: print('Where\'s the data?') raise inv_scores = (k / n) / (np.pi**( (p - 1) / 2) / gamma_func((p - 1) / 2 + 1) * knn**(p - 1)) return 1 / inv_scores
def __init__(self, alpha, D, n_iter, T, covariance_type='diagonal'): self.alpha = alpha #Dirichlet concentration parameter self.D = D self.Dfl = tf.cast(self.D, dtype=tf.float32) #dimensionality of data self.T = T #truncation value self.gaussian_const = np.divide( gamma_func(1.5) * (2.0**1.5), np.sqrt(2. * np.pi)) #Initialization settings self.mu_std = 5. #inference settings self.n_iter = n_iter self.log_constant = 1e-30
def test_SP_TanhSinh(): s = -0.5 wc = 5 tmax = 25 sd = lambda w: w**s*np.exp(-w/wc) bcf = lambda tau: (wc/(1+1j*wc*tau))**(s+1)*gamma_func(s+1)/np.pi _sp = sp.StocProc_TanhSinh(spectral_density=sd, t_max=tmax, bcf_ref=bcf, intgr_tol=1e-2, intpl_tol=1e-2, seed=0) d_tol = [0.09, 0.05] for j, N in enumerate([1000, 5000]): t = np.linspace(0, tmax, 500) idx = 200 c = 0 for i in range(N): _sp.new_process() zt = _sp(t) c += zt*np.conj(zt[idx]) c /= N d = np.max(np.abs(c - bcf(t-t[idx]))) print(d) assert d < d_tol[j]
def _fs_low_frequency(self, frequency_array): """ Computes the free-space low-frequency approximation of the synchrotron radiation impedance, according to eq. 6.18 of [Murphy1997]_. .. math:: Z_{fs,approx}(f) / Z_0 = \frac{\Gamma\left( 2/3 \right) }{3^{1/3}} e^{i\pi/6} \left(\frac{f}{f_0}\right)^{1/3} This is a helper function. Parameters ---------- frequency_array : float array Frequencies at which to compute the impedance Returns ------- complex array impedance """ return self.Z0 * gamma_func(2/3) / 3**(1/3) * np.exp(1j*np.pi/6) \ * (frequency_array / self.f_0)**(1/3)
def __init__(self, k, theta): self.k = k self.theta = theta self.normalization = 1. / ((self.theta**self.k) * gamma_func(self.k)) self.log_normalization = np.log(self.normalization)
def _weibull_mean(shape, scale): r""" \mathrm{E}(X)=\lambda \Gamma\left(1+\frac{1}{k}\right) """ return scale * gamma_func(1 + 1 / shape)
def weibull_scale(mean, stdDev=None, cov=None): if stdDev is None: stdDev = cov * mean scale = lambda shape: mean / (gamma_func(1 + 1 / shape)) return scale(weibull_shape(mean, stdDev))
def gamma_intercept(N, slope, shape): '''Returns the intercept for the distribution in m^-4. N is the number concentration, slope is the distribution's slope parameter, and shape is the gamma shape paramter. All quantities should be in MKS.''' return N * slope ** (shape + 1) / gamma_func(shape + 1)
def I_k(k): """Integral from 0 to pi/2""" return np.sqrt(np.pi)*gamma_func(0.5*(k+1))/(4*gamma_func(0.5*k+2))
def scale_res(scale): res = scale - ((mu_sqrt_tau) / (gamma_func(mu_tau/scale + 0.5)/gamma_func(mu_tau/scale)))**2 return res
def calc_R_S_Haghighi(u, h_c, zm, rho, c_p, z0_soil=0.01, f_cover=0, w_C=1, c_d=0.2, a_r=3, a_s=5, k=0.1): """ Aerodynamic resistance at the soil boundary layer. Estimates the aerodynamic resistance at the soil boundary layer based on the soil resistance formulation adapted by [Li2019]_. Parameters ---------- u_star : float friction velocity (m s-1). h_C : float canopy height (m). z_0M : float aerodynamic roughness length for momentum trasport (m). d_0 : float zero-plane displacement height (m). zm : float height on measurement of wind speed (m). z0_soil : float, optional roughness length of the soil layer, use z0_soil=0.01. alpha_k : float, optional Heat diffusion coefficient, default=2. Returns ------- R_S : float Aerodynamic resistance at the soil boundary layer (s m-1). References ---------- ..[Li2019] Li, Yan, et al. "Evaluating Soil Resistance Formulations in Thermal?Based Two?Source Energy Balance (TSEB) Model: Implications for Heterogeneous Semiarid and Arid Regions." Water Resources Research 55.2 (2019): 1059-1078. https://doi.org/10.1029/2018WR022981. ..[Haghighi2015] Haghighi, Erfan, and Dani Or. "Interactions of bluff-body obstacles with turbulent airflows affecting evaporative fluxes from porous surfaces." Journal of Hydrology 530 (2015): 103-116. https://doi.org/10.1016/j.jhydrol.2015.09.048 ..[Haghighi2013] Haghighi, E., and Dani Or. "Evaporation from porous surfaces into turbulent airflows: Coupling eddy characteristics with pore scale vapor diffusion." Water Resources Research 49.12 (2013): 8432-8442. https://doi.org/10.1002/2012WR013324. % ------------------------------------------------------------------------- % Inputs | Description % ------------------------------------------------------------------------- % ps | mean particle size of soil [m] % n | soil pore size distribution index [-] % phi | porosity [-] % theta | soil water content [m3 m-3] % theta_res | residual water content [m3 m-3] % z_w | measurement height [m] % U | wind velocity [m s-1] % eta | vegetation cover fraction [-] =0 for bare soil % h | (cylindrical) vegettaion height [m] =0 for bare soil % d | (cylindrical) vegetation diameter [m] =0 for bare soil % ------------------------------------------------------------------------- """ def calc_prod_alpha(alpha, n): out = 1.0 for i in range(n): out = out * (2 * (alpha - i) + 1) return out def calc_prod_alpha_array(alpha_array): out_array = np.ones(alpha_array.shape) n_array = np.ceil(alpha_array).astype(np.int) ns = np.unique(n_array) for n in ns: index = n_array == n out_array[index] = calc_prod_alpha(alpha_array[index], n) return out_array # Define constanst nu = 15.11e-6 # [m2 s-1] kinmeatic visocosity of air k_a = 0.024 # [W m-1 K-1] thermal conductivity of air c_2 = 2.2 c_3 = 112. g_alpha = 21.7 u, h_c, zm, z0_soil, f_cover, w_C = map( np.asarray, (u, h_c, zm, z0_soil, f_cover, w_C)) width = h_c * w_C a_veg = (np.pi / 4) * width**2 lambda_ = width * h_c * f_cover / a_veg h_c[f_cover == 0] = 0 lambda_[f_cover == 0] = 0 z_0sc = z0_soil * (1 + f_cover * ((zm - h_c) / zm - 1)) f_r = np.exp(-a_r * lambda_ / (1. - f_cover)**k) f_s = np.exp(-a_s * lambda_ / (1. - f_cover)**k) c_sgc = KARMAN**2 * (np.log((zm - h_c) / z_0sc))**-2 c_sg = KARMAN**2 * (np.log(zm / z0_soil))**-2 f_v = 1. + f_cover * (c_sgc / c_sg - 1.) beta = (c_d / KARMAN**2) * ((np.log(h_c / z0_soil) - 1)**2 + 1) c_rg = beta * c_sg alpha_mean = (0.3 / np.sqrt(f_r * lambda_ * (1. - f_cover) * c_rg + (f_s * (1. - f_cover) + f_v * f_cover) * c_sg)) - 1 u_star = (u * np.sqrt(f_r * lambda_ * (1. - f_cover) * c_rg + (f_s * (1 - f_cover) + f_v * f_cover) * c_sg)) prod_alpha = calc_prod_alpha_array(alpha_mean) g_alpha = c_2 * np.sqrt( c_3 * np.pi) / (gamma_func(alpha_mean + 1) * 2**(alpha_mean + 1) * np.sqrt(alpha_mean + 1)) g_alpha[ alpha_mean > 0] = g_alpha[alpha_mean > 0] * prod_alpha[alpha_mean > 0] delta = g_alpha * nu / u_star r_s = rho * c_p * delta / k_a return np.asarray(r_s)
def bcf(tau): s = -0.5 wc = 5 return (wc/(1+1j*wc*tau))**(s+1)*gamma_func(s+1)/np.pi
def test_stochastic_process_FFT_interpolation(plot=False): s_param = 0.7 gamma_s_plus_1 = gamma(s_param+1) # two parameter correlation function -> correlation matrix r_tau = lambda tau : corr(tau, s_param, gamma_s_plus_1) J = lambda w : spectral_density(w, s_param) eta = 0.1 s = 0.7 gamma_param = 2. from scipy.special import gamma as gamma_func _c1 = eta * gamma_param**(s+1) / np.pi _c3 = gamma_func(s + 1) r_tau = lambda tau: _c1 * (1 + 1j*gamma_param * tau)**(-(s+1)) * _c3 J = lambda w: eta * w**s * np.exp(-w/gamma_param) # time interval [0,T] t_max = 30 # number of subintervals # leads to N+1 grid points ng = 100 ng_fine = ng*3 seed = 0 stoc_proc = sp.class_stocproc.StocProc_FFT(spectral_density = J, t_max = t_max, num_grid_points = ng, seed = seed, verbose = 1) finer_t = np.linspace(0, t_max, ng_fine) ns = 10000 ac_conj = np.zeros(shape=(ng_fine, ng_fine), dtype=np.complex) ac_not_conj = np.zeros(shape=(ng_fine, ng_fine), dtype=np.complex) print("generate samples ...") for n in range(ns): stoc_proc.new_process() x_t = stoc_proc(finer_t) ac_conj += x_t.reshape(ng_fine, 1) * np.conj(x_t.reshape(1, ng_fine)) ac_not_conj += x_t.reshape(ng_fine, 1) * x_t.reshape(1, ng_fine) print("done!") ac_conj /= ns ac_not_conj /= ns t_grid = np.linspace(0, t_max, ng_fine) ac_true = r_tau(t_grid.reshape(ng_fine, 1) - t_grid.reshape(1, ng_fine)) max_diff_conj = np.max(np.abs(ac_true - ac_conj)) print("max diff <x(t) x^ast(s)>: {:.2e}".format(max_diff_conj)) max_diff_not_conj = np.max(np.abs(ac_not_conj)) print("max diff <x(t) x(s)>: {:.2e}".format(max_diff_not_conj)) if plot: v_min_real = np.floor(np.min(np.real(ac_true))) v_max_real = np.ceil(np.max(np.real(ac_true))) v_min_imag = np.floor(np.min(np.imag(ac_true))) v_max_imag = np.ceil(np.max(np.imag(ac_true))) fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(10,12)) fig.suptitle("ns:{}, ng:{}, ng_fine:{}".format(ns, ng, ng_fine)) ax[0,0].set_title(r"exact $\mathrm{re}\left(\langle x(t) x^\ast(s) \rangle\right)$") ax[0,0].imshow(np.real(ac_true), interpolation='none', vmin=v_min_real, vmax=v_max_real) ax[0,1].set_title(r"exact $\mathrm{im}\left(\langle x(t) x^\ast(s) \rangle\right)$") ax[0,1].imshow(np.imag(ac_true), interpolation='none', vmin=v_min_imag, vmax=v_max_imag) ax[1,0].set_title(r"FFT $\mathrm{re}\left(\langle x(t) x^\ast(s) \rangle\right)$") ax[1,0].imshow(np.real(ac_conj), interpolation='none', vmin=v_min_real, vmax=v_max_real) ax[1,1].set_title(r"FFT $\mathrm{im}\left(\langle x(t) x^\ast(s) \rangle\right)$") ax[1,1].imshow(np.imag(ac_conj), interpolation='none', vmin=v_min_imag, vmax=v_max_imag) ax[2,0].set_title(r"FFT $\mathrm{re}\left(\langle x(t) x(s) \rangle\right)$") ax[2,0].imshow(np.real(ac_not_conj), interpolation='none', vmin=v_min_real, vmax=v_max_real) ax[2,1].set_title(r"FFT $\mathrm{im}\left(\langle x(t) x(s) \rangle\right)$") ax[2,1].imshow(np.imag(ac_not_conj), interpolation='none', vmin=v_min_imag, vmax=v_max_imag) ax[0,2].set_title(r"FFT log rel diff") im02 = ax[0,2].imshow(np.log10(np.abs(ac_conj - ac_true) / np.abs(ac_true)), interpolation='none') divider02 = make_axes_locatable(ax[0,2]) cax02 = divider02.append_axes("right", size="10%", pad=0.05) cbar02 = plt.colorbar(im02, cax=cax02) ax[1,2].set_title(r"FFT rel diff") im12 = ax[1,2].imshow(np.abs(ac_conj - ac_true) / np.abs(ac_true), interpolation='none') divider12 = make_axes_locatable(ax[1,2]) cax12 = divider12.append_axes("right", size="10%", pad=0.05) cbar12 = plt.colorbar(im12, cax=cax12) ax[2,2].set_title(r"FFT abs diff") im22 = ax[2,2].imshow(np.abs(ac_conj - ac_true), interpolation='none') divider22 = make_axes_locatable(ax[2,2]) cax22 = divider22.append_axes("right", size="10%", pad=0.05) cbar22 = plt.colorbar(im22, cax=cax22) # fig2, ax2 = plt.subplots(nrows=1, ncols=1) # # # i = 30 # tau = t_grid - t_grid[i] # # ax2.plot(t_grid, np.abs(r_tau(tau))) # # ax2.plot(t_grid, np.abs(np.mean(x_t_samples*np.conj(x_t_samples[:,i].reshape(ns,1)), axis=0))) plt.show() assert max_diff_not_conj < 4e-2 assert max_diff_conj < 4e-2
def __init__(self, pts, k=None, r=None, kmax=None, rmax=None): """ Parameters ---------- pts : array, shape(n, d) Data points. Should be already normalized if necessary. k : int Neighbors used to estimate the local density rho. kmax : int If given, only search the nearest kmax neighbors to calculate delta. kmax is equivalent to search a sphere of size about kmax**(1/d) times the local average separation between points. Default is to search all points. rmax : float If given, only search the neighbors within rmax to calculate delta. Default is to search all points. Todos ----- Optimal choice of k and gamma Performance optimization with Cython or Numba Substructure within density saddle point Labeling the noise """ if (k is not None) and (r is not None): raise ValueError("Only one of 'k' or 'r' can be specified!") if (kmax is not None) and (rmax is not None): raise ValueError("Only one of 'kmax' or 'rmax' can be specified!") pts = np.asfarray(pts) npts, ndim = pts.shape Rmax = np.linalg.norm(pts.max(0) - pts.min(0)) tree = KDTree(pts) # density if r is not None: k = tree.query_radius(pts, r, count_only=True) elif k is not None: r = tree.query(pts, k)[0][:, -1] sphere_coeff = np.pi**(0.5 * ndim) / gamma_func(0.5 * ndim + 1) rho = k / (sphere_coeff * r**ndim) rho[rho == 0] = rho[rho > 0].min() / 2 # reduce by an arbitrary factor # delta delta = np.full(npts, Rmax, dtype='float') chief = np.full(npts, -1, dtype='int') # superior neighbor if kmax is not None or rmax is not None: if kmax is not None: dists, index = tree.query( pts, kmax, return_distance=True, sort_results=True) else: index, dists = tree.query_radius( pts, rmax, return_distance=True, sort_results=True) for i in range(npts): rho_i = rho[i] for j, dist in zip(index[i], dists[i]): if (rho[j] > rho_i): chief_i, delta_i = j, dist break chief[i], delta[i] = chief_i, delta_i else: dists = squareform(pdist(pts)) for i in range(npts): rho_i, delta_i = rho[i], delta[i] for j, dist in enumerate(dists[i]): if (rho[j] > rho_i) and (dist < delta_i): chief_i, delta_i = j, dist chief[i], delta[i] = chief_i, delta_i # gamma gamma = sphere_coeff * rho * delta**ndim # need sphere_coeff? sorted_index = np.argsort(gamma) sorted_gamma = gamma[sorted_index] # properties self.npts = npts self.ndim = ndim self.pts = pts self.rho = rho self.delta = delta self.gamma = gamma self.chief = chief self.sorted_index = sorted_index self.sorted_gamma = sorted_gamma