def Ie(self,n,z): """even first-kind radial Mathieu function (Ie) analogous to I Bessel functions, called Ce in McLachlan p248 (eq 1&2), for scalar or vector orders or argument n: order (scalar or vector) z: radial argument (scalar or vector)""" from scipy.special import ive n,z,sqrtq,v1,v2,M,EV,OD = self._RadFuncSetup(n,z) y = np.empty((n.shape[0],z.shape[0]),dtype=complex) ord = self.ord[0:M+1] sgn = self.sgnord[0:M,None,None] I1 = ive(ord[0:M+1,None],v1[None,:])[:,None,:] I2 = ive(ord[0:M+1,None],v2[None,:])[:,None,:] j = n[:]//2 y[EV,:] = (np.sum(sgn*self.A[0:M,j[EV],0,:]*I1[0:M,:,:]*I2[0:M,:,:],axis=0)/ self.A[0,j[EV],0,:]) y[OD,:] = (np.sum(sgn*self.B[0:M,j[OD],1,:] * (I1[0:M,:,:]*I2[1:M+1,:,:] + I1[1:M+1,:,:]*I2[0:M,:,:]),axis=0)/ self.B[0,j[OD],1,:]) # scaling factor to un-scale products of Bessel functions from ive() y *= np.exp(np.abs(v1.real) + np.abs(v2.real))[None,:] return np.squeeze(y)
def Io(self,n,z): """odd first-kind radial Mathieu function (Io) analogous to I Bessel functions, called Se in McLachlan p248 (eq 3&4), for scalar or vector orders or argument n: order (scalar or vector) z: radial argument (scalar or vector)""" from scipy.special import ive n,z,sqrtq,v1,v2,M,EV,OD = self._RadFuncSetup(n,z) y = np.empty((n.shape[0],z.shape[0]),dtype=complex) ord = self.ord[0:M+2] sgn = self.sgnord[0:M,None,None] I1 = ive(ord[0:M+2,None],v1[None,:])[:,None,:] I2 = ive(ord[0:M+2,None],v2[None,:])[:,None,:] j = (n[:]-1)//2 # Io_0() invalid y[EV,:] = (np.sum(sgn*self.B[0:M,j[EV],0,:] * (I1[0:M,:,:]*I2[2:M+2,:,:] - I1[2:M+2,:,:]*I2[0:M,:,:]),axis=0)/ self.B[0,j[EV],0,:]) y[OD,:] = (np.sum(sgn*self.A[0:M,j[OD],1,:] * (I1[0:M,:,:]*I2[1:M+1,:,:] - I1[1:M+1,:,:]*I2[0:M,:,:]),axis=0)/ self.A[0,j[OD],1,:]) y *= np.exp(np.abs(v1.real) + np.abs(v2.real))[None,:] y[n==0,:] = np.NaN return np.squeeze(y)
def dIo(self,n,z): """odd first-kind radial Mathieu function derivative (DIo) (analogous to I Bessel functions, called Se in McLachlan p248), for scalar or vector orders or argument n: order (scalar or vector) z: radial argument (scalar or vector)""" from scipy.special import ive n,z,sqrtq,enz,epz,v1,v2,M,EV,OD = self._RadDerivFuncSetup(n,z) dy = np.empty((n.shape[0],z.shape[0]),dtype=complex) ord = self.ord[0:M+2] sgn = self.sgnord[0:M,None,None] I1 = ive(ord[0:M+2,None],v1[None,:])[:,None,:] I2 = ive(ord[0:M+2,None],v2[None,:])[:,None,:] dI1 = self._deriv(v1,I1[0:M+2,0,:],0)[:,None,:] dI2 = self._deriv(v2,I2[0:M+2,0,:],0)[:,None,:] j = (n[:]-1)//2 dy[EV,:] = (sqrtq/self.B[0,j[EV],0,:]*np.sum(sgn*self.B[0:M,j[EV],0,:] * (epz*I1[0:M,:,:]*dI2[2:M+2,:,:] - enz*dI1[0:M,:,:]*I2[2:M+2,:,:] - (epz*I1[2:M+2,:,:]*dI2[0:M,:,:] - enz*dI1[2:M+2,:,:]*I2[0:M,:,:])),axis=0)) dy[OD,:] = (sqrtq/self.A[0,j[OD],1,:]*np.sum(sgn*self.A[0:M,j[OD],1,:] * (epz*I1[0:M,:,:]*dI2[1:M+1,:,:] - enz*dI1[0:M,:,:]*I2[1:M+1,:,:] - (epz*I1[1:M+1,:,:]*dI2[0:M,:,:] - enz*dI1[1:M+1,:,:]*I2[0:M,:,:])),axis=0)) dy *= np.exp(np.abs(v1.real) + np.abs(v2.real))[None,:] dy[n==0,:] = np.NaN # dIo_0() invalid return np.squeeze(dy)
def dKo(self,n,z): """odd second-kind radial Mathieu function derivative (DKo) (analogous to K Bessel functions, called Gek in McLachlan p248), for scalar or vector orders or argument n: order (scalar or vector) z: radial argument (scalar or vector)""" from scipy.special import kve,ive n,z,sqrtq,enz,epz,v1,v2,M,EV,OD = self._RadDerivFuncSetup(n,z) dy = np.empty((n.shape[0],z.shape[0]),dtype=complex) ord = self.ord[0:M+2] I = ive(ord[0:M+2,None],v1[None,:])[:,None,:] K = kve(ord[0:M+2,None],v2[None,:])[:,None,:] dI = self._deriv(v1,I[0:M+2,0,:],0)[:,None,:] dK = self._deriv(v2,K[0:M+2,0,:],1)[:,None,:] j = (n[:]-1)//2 dy[EV,:] = (sqrtq/self.B[0,j[EV],0,:]*np.sum(self.B[0:M,j[EV],0,:] * (epz*I[0:M,:,:]*dK[2:M+2,:,:] - enz*dI[0:M,:,:]*K[2:M+2,:,:] - (epz*I[2:M+2,:,:]*dK[0:M,:,:] - enz*dI[2:M+2,:,:]*K[0:M,:,:])),axis=0)) dy[OD,:] = (sqrtq/self.A[0,j[OD],1,:]*np.sum(self.A[0:M,j[OD],1,:] * (epz*I[0:M,:,:]*dK[1:M+1,:,:] - enz*dI[0:M,:,:]*K[1:M+1,:,:] + epz*I[1:M+1,:,:]*dK[0:M,:,:] - enz*dI[1:M+1,:,:]*K[0:M,:,:]),axis=0)) dy *= np.exp(np.abs(v1.real) - v2)[None,:] dy[n==0,:] = np.NaN # dKo_0() invalid return np.squeeze(dy)
def __init__(self,pset,psf_model): PDF.__init__(self,pset) self._psf_model = copy.deepcopy(psf_model) # self._pid = [pnorm.pid(),psigma.pid()] x = np.linspace(-4,4,800) self._ive = UnivariateSpline(x,spfn.ive(0,10**x),s=0,k=2)
def Ko(self,n,z): """odd second-kind radial Mathieu function (Ko) (analogous to K Bessel functions, called Gek in McLachlan p248), for scalar or vector orders or argument n: order (scalar or vector) z: radial argument (scalar or vector)""" from scipy.special import kve,ive n,z,sqrtq,v1,v2,M,EV,OD = self._RadFuncSetup(n,z) y = np.empty((n.shape[0],z.shape[0]),dtype=complex) ord = self.ord[0:M+2] I = ive(ord[0:M+2,None],v1[None,:])[:,None,:] K = kve(ord[0:M+2,None],v2[None,:])[:,None,:] j = (n[:]-1)//2 y[EV,:] = (np.sum(self.B[0:M,j[EV],0,:] * (I[0:M,:,:]*K[2:M+2,:,:] - I[2:M+2,:,:]*K[0:M,:,:]),axis=0)/ self.B[0,j[EV],0,:]) y[OD,:] = (np.sum(self.A[0:M,j[OD],1,:] * (I[0:M,:,:]*K[1:M+1,:,:] + I[1:M+1,:,:]*K[0:M,:,:]),axis=0)/ self.A[0,j[OD],1,:]) y *= np.exp(np.abs(v1.real) - v2)[None,:] y[n==0,:] = np.NaN # Ko_0() invalid return np.squeeze(y)
def convolve2d_gauss(fn, r, sig, nstep=200): """Evaluate the convolution f'(r) = f(r) * g(r) where f(r) is azimuthally symmetric function in two dimensions and g is a 2D gaussian with standard deviation s given by: g(r) = 1/(2*pi*s^2) Exp[-r^2/(2*s^2)] Parameters ---------- fn : function Input function that takes a single radial coordinate parameter. r : `~numpy.ndarray` Array of points at which the convolution is to be evaluated. sig : float Width parameter of the gaussian. nstep : int Number of sampling point for numeric integration. """ r = np.array(r, ndmin=1) sig = np.array(sig, ndmin=1) rmin = r - 10 * sig rmax = r + 10 * sig rmin[rmin < 0] = 0 delta = (rmax - rmin) / nstep redge = (rmin[:, np.newaxis] + delta[:, np.newaxis] * np.linspace(0, nstep, nstep + 1)[np.newaxis, :]) rp = 0.5 * (redge[:, 1:] + redge[:, :-1]) dr = redge[:, 1:] - redge[:, :-1] fnv = fn(rp) r = r.reshape(r.shape + (1,)) saxis = 1 sig2 = sig * sig x = r * rp / (sig2) if 'je_fn' not in convolve2d_gauss.__dict__: t = 10 ** np.linspace(-8, 8, 1000) t = np.insert(t, 0, [0]) je = special.ive(0, t) convolve2d_gauss.je_fn = UnivariateSpline(t, je, k=2, s=0) je = convolve2d_gauss.je_fn(x.flat).reshape(x.shape) # je2 = special.ive(0,x) v = (rp * fnv / (sig2) * je * np.exp(x - (r * r + rp * rp) / (2 * sig2)) * dr) s = np.sum(v, axis=saxis) return s
def Fm(x, m, r1, r2, semi = True): ra = r1 rb = r2 if (r2 < r1): rb = r1 ra = r2 if m > 20 and semi: za = x * ra zb = x * rb if (za < 1e-5) and (zb < 1e-5): e = -1 + m * math.log(ra/rb * (m + 1.0)/m) -0.5 *math.log((m+1.0)*m) - math.log(rb/2/(m + 1.0)) return -math.exp(2*e)/4.0 #return 0.0 sqa1 = math.sqrt(m**2 + za**2) sqa2 = math.sqrt((m + 1)**2 + za**2) sqb1 = math.sqrt(m**2 + zb**2) sqb2 = math.sqrt((m + 1)**2 + zb**2) li1 = sqa1 + m * math.log(za/(m + sqa1)) - 0.5 * math.log(sqa1) li2 = sqa2 + (m + 1) * math.log(za/(m + 1 + sqa2)) - 0.5 * math.log(sqa2) lk1 = -sqb1 - m * math.log(zb/(m + sqb1)) - 0.5 * math.log(sqb1) lk2 = -sqb2 - (m + 1)* math.log(zb/(m + 1 + sqb2)) - 0.5 * math.log(sqb2) L = 2.0*(li1 + lk1) Li = 2.0*(li2 - li1) Lk = 2.0*(lk2 - lk1) return math.exp(L) * x * x * (math.exp(Li) - 1) * (math.exp(Lk) - 1)/4 #return math.exp(L) * (math.exp(Li) - 1) * (math.exp(Lk) - 1)/4 im1 = special.ive(m, x * ra) km1 = special.kve(m, x * rb) im2 = special.ive(m + 1, x * ra) km2 = special.kve(m + 1, x * rb) e = math.exp(x * (ra - rb)) q1 = im1 * km1 * im1 * km1 q2 = im2 * km2 * im2 * km2 q3 = im1 * km2 * im1 * km2 #q4 = q3 q4 = im2 * km1 * im2 * km1 #q = x * (im1 * km1 - im2 * km2) * e #print r1, r2, m, e, q return x * x * (im1 * im1 - im2 * im2) * (km2 * km2 - km1 * km1) * e * e
def make_Ive_array(kperp,nb,Tpar_Tperp): global ive_arr ive_arr = np.empty((2*nb+2),dtype=np.float64) b=0.5*kperp**2/Tpar_Tperp js=np.arange(0,2*nb+2) j_shift=js-nb-1 for j in js: ive_arr[j] = ive(j_shift[j],b)
def convolve2d_gauss(fn,r,sig,rmax,nstep=200): """Evaluate the convolution f'(r) = f(r) * g(r) where f(r) is azimuthally symmetric function in two dimensions and g is a gaussian given by: g(r) = 1/(2*pi*s^2) Exp[-r^2/(2*s^2)] Parameters ---------- fn : Input function that takes a single radial coordinate parameter. r : Array of points at which the convolution is to be evaluated. sig : Width parameter of the gaussian. """ r = np.array(r,ndmin=1,copy=True) sig = np.array(sig,ndmin=1,copy=True) rp = edge_to_center(np.linspace(0,rmax,nstep+1)) dr = rmax/float(nstep) fnrp = fn(rp) if sig.shape[0] > 1: rp = rp.reshape((1,1,nstep)) fnrp = fnrp.reshape((1,1,nstep)) r = r.reshape((1,r.shape[0],1)) sig = sig.reshape(sig.shape + (1,1)) saxis = 2 else: rp = rp.reshape(1,nstep) fnrp = fnrp.reshape(1,nstep) r = r.reshape(r.shape + (1,)) saxis = 1 sig2 = sig*sig x = r*rp/(sig2) je = spfn.ive(0,x) s = np.sum(rp*fnrp/(sig2)* np.exp(np.log(je)+x-(r*r+rp*rp)/(2*sig2)),axis=saxis)*dr return s
def _verifyPdfWithNumpy(self, vmf, atol=1e-4): """Verifies log_prob evaluations with numpy/scipy. Both uniform random points and sampled points are evaluated. Args: vmf: A `tfp.distributions.VonMisesFisher` instance. atol: Absolute difference tolerable. """ dim = tf.compat.dimension_value(vmf.event_shape[-1]) nsamples = 10 # Sample some random points uniformly over the hypersphere using numpy. sample_shape = [nsamples] + tensorshape_util.as_list( vmf.batch_shape) + [dim] uniforms = np.random.randn(*sample_shape) uniforms /= np.linalg.norm(uniforms, axis=-1, keepdims=True) uniforms = uniforms.astype(dtype_util.as_numpy_dtype(vmf.dtype)) # Concatenate in some sampled points from the distribution under test. vmf_samples = vmf.sample( sample_shape=[nsamples], seed=tfp_test_util.test_seed()) samples = tf.concat([uniforms, vmf_samples], axis=0) samples = tf.debugging.check_numerics(samples, 'samples') samples = self.evaluate(samples) log_prob = vmf.log_prob(samples) log_prob = tf.debugging.check_numerics(log_prob, 'log_prob') conc = self.evaluate(vmf.concentration) mean_dir = self.evaluate(vmf.mean_direction) log_true_sphere_surface_area = ( np.log(2) + (dim / 2) * np.log(np.pi) - sp_special.gammaln(dim / 2)) expected = ( conc * np.sum(samples * mean_dir, axis=-1) + np.where(conc > 0, (dim / 2 - 1) * np.log(conc) - (dim / 2) * np.log(2 * np.pi) - np.log(sp_special.ive(dim / 2 - 1, conc)) - np.abs(conc), -log_true_sphere_surface_area)) self.assertAllClose(expected, self.evaluate(log_prob), atol=atol)
def dKo(self, n, z): """odd second-kind radial Mathieu function derivative (DKo) (analogous to K Bessel functions, called Gek in McLachlan p248), for scalar or vector orders or argument n: order (scalar or vector) z: radial argument (scalar or vector)""" from scipy.special import kve, ive n, z, sqrtq, enz, epz, v1, v2, M, EV, OD = self._RadDerivFuncSetup( n, z) dy = np.empty((n.shape[0], z.shape[0]), dtype=complex) ord = self.ord[0:M + 2] I = ive(ord[0:M + 2, None], v1[None, :])[:, None, :] K = kve(ord[0:M + 2, None], v2[None, :])[:, None, :] dI = self._deriv(v1, I[0:M + 2, 0, :], 0)[:, None, :] dK = self._deriv(v2, K[0:M + 2, 0, :], 1)[:, None, :] j = (n[:] - 1) // 2 dy[EV, :] = (sqrtq / self.B[0, j[EV], 0, :] * np.sum(self.B[0:M, j[EV], 0, :] * (epz * I[0:M, :, :] * dK[2:M + 2, :, :] - enz * dI[0:M, :, :] * K[2:M + 2, :, :] - (epz * I[2:M + 2, :, :] * dK[0:M, :, :] - enz * dI[2:M + 2, :, :] * K[0:M, :, :])), axis=0)) dy[OD, :] = (sqrtq / self.A[0, j[OD], 1, :] * np.sum( self.A[0:M, j[OD], 1, :] * (epz * I[0:M, :, :] * dK[1:M + 1, :, :] - enz * dI[0:M, :, :] * K[1:M + 1, :, :] + epz * I[1:M + 1, :, :] * dK[0:M, :, :] - enz * dI[1:M + 1, :, :] * K[0:M, :, :]), axis=0)) dy *= np.exp(np.abs(v1.real) - v2)[None, :] dy[n == 0, :] = np.NaN # dKo_0() invalid return np.squeeze(dy)
def _verifyPdfWithNumpy(self, vmf, atol=1e-4): """Verifies log_prob evaluations with numpy/scipy. Both uniform random points and sampled points are evaluated. Args: vmf: A `tfp.distributions.VonMisesFisher` instance. atol: Absolute difference tolerable. """ dim = vmf.event_shape[-1].value nsamples = 10 # Sample some random points uniformly over the hypersphere using numpy. sample_shape = [nsamples] + vmf.batch_shape.as_list() + [dim] uniforms = np.random.randn(*sample_shape) uniforms /= np.linalg.norm(uniforms, axis=-1, keepdims=True) uniforms = uniforms.astype(vmf.dtype.as_numpy_dtype) # Concatenate in some sampled points from the distribution under test. samples = tf.concat( [uniforms, vmf.sample(sample_shape=[nsamples])], axis=0) samples = tf.check_numerics(samples, 'samples') samples = self.evaluate(samples) log_prob = vmf.log_prob(samples) log_prob = tf.check_numerics(log_prob, 'log_prob') try: from scipy.special import gammaln # pylint: disable=g-import-not-at-top from scipy.special import ive # pylint: disable=g-import-not-at-top except ImportError: tf.logging.warn('Unable to use scipy in tests') return conc = self.evaluate(vmf.concentration) mean_dir = self.evaluate(vmf.mean_direction) log_true_sphere_surface_area = (np.log(2) + (dim / 2) * np.log(np.pi) - gammaln(dim / 2)) expected = (conc * np.sum(samples * mean_dir, axis=-1) + np.where( conc > 0, (dim / 2 - 1) * np.log(conc) - (dim / 2) * np.log(2 * np.pi) - np.log(ive(dim / 2 - 1, conc)) - np.abs(conc), -log_true_sphere_surface_area)) self.assertAllClose(expected, self.evaluate(log_prob), atol=atol)
def vmf_tic(X): X = np.array(X) ll = log_likelihood(X) if np.isnan(ll): return np.nan N, D = X.shape mu = fit_mean_direction(X) kappa = fit_concentration(X) total = np.zeros(D) hess_diagonal = np.zeros(D - 1) for i, x in enumerate(X): grad_i = log_vMF_gradient(mu, kappa, x) total += grad_i**2 elementwise = x * mu cdots = np.cumsum(elementwise[::-1])[::-1] hess_diagonal += -cdots[:-1] * kappa total /= N hess_diagonal /= N v = (D / 2 - 1) num = ive(v + 1, kappa) * (ive(v - 1, kappa) + ive(v + 1, kappa)) - ive( v, kappa) * (ive(v, kappa) + ive(v + 2, kappa)) # noqa denom = 2 * ive(v, kappa)**2 k_diag = num / denom fisher_diagonal = -np.concatenate([[k_diag], hess_diagonal]) correction = np.sum(total / fisher_diagonal) return -(ll - correction)
def magnetic_field_vertical_magnetic_dipole(t, xy, sigma=1.0, mu=mu_0, moment=1.0): """Magnetic field due to step off vertical dipole at the surface Parameters ---------- t : (n_t) numpy.ndarray times (s) xy : (n_locs, 2) numpy.ndarray surface field locations (m) sigma : float, optional conductivity mu : float, optional magnetic permeability moment : float, optional moment of the dipole Returns ------- h : (n_t, n_locs, 3) numpy.ndarray The magnetic field at the observation locations and times. Notes ----- Matches the negative of equation 4.69a of Ward and Hohmann 1988, for the vertical component (due to the difference in coordinate sign conventionn used here). .. math:: h_z = -\\frac{m}{4 \\pi \\rho^2} \\left[ \\left(\\frac{9}{2 \\theta^2 \\rho^2} - 1\\right)\\mathrm{erf}(\\theta \\rho) - \\frac{1}{\\sqrt{\\pi}}\\left(\\frac{9}{\\theta \\rho + 4 \\theta \\rho} \\right) e^{-\\theta^2\\rho^2} \\right] Also matches equation 4.72 for the horizontal components, which is again negative due to our coordinate convention. .. math:: h_\\rho = \\frac{m \\theta^2}{2\\pi\\rho} e^{-\\theta^2\\rho^2/2}\\left[I_1\\left(\\frac{\\theta^2\\rho^2}{2}\\right) - I_2\\left(\\frac{\\theta^2\\rho^2}{2}\\right)\\right] Examples -------- Reproducing part of Figure 4.4 and 4.5 from Ward and Hohmann 1988 >>> import numpy as np >>> import matplotlib.pyplot as plt >>> from geoana.em.tdem import magnetic_field_vertical_magnetic_dipole Calculate the field at the time given, and 100 m along the x-axis, >>> times = np.logspace(-8, 0, 200) >>> xy = np.array([[100, 0, 0]]) >>> h = magnetic_field_vertical_magnetic_dipole(times, xy, sigma=1E-2) Match the vertical magnetic field plot >>> plt.loglog(times*1E3, h[:,0, 2], c='C0', label='$h_z$') >>> plt.loglog(times*1E3, -h[:,0, 2], '--', c='C0') >>> plt.loglog(times*1E3, h[:,0, 0], c='C1', label='$h_x$') >>> plt.loglog(times*1E3, -h[:,0, 0], '--', c='C1') >>> plt.xlabel('time (ms)') >>> plt.ylabel('h (A/m)') >>> plt.legend() >>> plt.show() """ r = np.linalg.norm(xy[:, :2], axis=-1) x = xy[:, 0] y = xy[:, 1] thr = theta(t, sigma, mu=mu)[:, None] * r #will be positive... h_z = 1.0 / r**3 * ((9 / (2 * thr**2) - 1) * erf(thr) - (9 / thr + 4 * thr) / np.sqrt(np.pi) * np.exp(-thr**2)) # positive here because z+ up # iv(1, arg) - iv(2, arg) # ive(1, arg) * np.exp(abs(arg)) - ive(2, arg) * np.exp(abs(arg)) # (ive(1, arg) - ive(2, arg))*np.exp(abs(arg)) h_r = 2 * thr**2 / r**3 * (ive(1, thr**2 / 2) - ive(2, thr**2 / 2)) # thetar is always positive so this above simplifies (more numerically stable) angle = np.arctan2(y, x) h_x = np.cos(angle) * h_r h_y = np.sin(angle) * h_r return moment / (4 * np.pi) * np.stack((h_x, h_y, h_z), axis=-1)
def halfspace(off, angle, zsrc, zrec, etaH, etaV, freqtime, ab, signal, solution='dhs'): """Return frequency- or time-space domain VTI half-space solution. Calculates the frequency- or time-space domain electromagnetic response for a half-space below air using the diffusive approximation, as given in [Slob_et_al_2010]_, where the electric source is located at [0, 0, zsrc], and the electric receiver at [xco, yco, zrec]. It can also be used to calculate the fullspace solution or the separate fields: direct field, reflected field, and airwave; always using the diffusive approximation. See `solution`-parameter. This routine is not strictly part of `empymod` and not used by it. However, it can be useful to compare the code to this analytical solution. This function is called from one of the modelling routines in :mod:`model`. Consult these modelling routines for a description of the input and solution parameters. """ xco = np.cos(angle) * off yco = np.sin(angle) * off res = np.real(1 / etaH[0, 0]) aniso = 1 / np.sqrt(np.real(etaV[0, 0]) * res) # Define freq/time and dtype depending on signal. if signal is None: freq = freqtime dtype = complex else: time = freqtime if signal == -1: # Calculate DC time = np.r_[time[:, 0], 1e4][:, None] freqtime = time dtype = float # Other defined parameters rh = np.sqrt(xco**2 + yco**2) # Horizontal distance in space hp = np.abs(zrec + zsrc) # Physical vertical distance hm = np.abs(zrec - zsrc) hsp = hp * aniso # Scaled vertical distance hsm = hm * aniso rp = np.sqrt(xco**2 + yco**2 + hp**2) # Physical distance rm = np.sqrt(xco**2 + yco**2 + hm**2) rsp = np.sqrt(xco**2 + yco**2 + hsp**2) # Scaled distance rsm = np.sqrt(xco**2 + yco**2 + hsm**2) # tp = mu_0 * rp**2 / (res * 4) # Diffusion time tm = mu_0 * rm**2 / (res * 4) tsp = mu_0 * rsp**2 / (res * aniso**2 * 4) # Scaled diffusion time tsm = mu_0 * rsm**2 / (res * aniso**2 * 4) # if signal is None: s = 2j * np.pi * freq # Laplace parameter # delta-fct delta_\alpha\beta if ab in [11, 22, 33]: delta = 1 else: delta = 0 # src-rec type if ab == 33: srcrec = 3 elif ab in [13, 23, 31, 32]: srcrec = 2 else: srcrec = 1 # Define alpha/beta; swap if necessary x = xco y = yco if ab == 11: y = x elif ab in [22, 23, 32]: x = y elif ab == 21: x, y = y, x # Define rev for 3\alpha->\alpha3 reciprocity if ab in [13, 23]: rev = -1 elif ab in [31, 32]: rev = 1 # Exponential diffusion functions for m=0,1,2 if signal is None: # Frequency-domain f0p = np.exp(-2 * np.sqrt(s * tp)) f0m = np.exp(-2 * np.sqrt(s * tm)) fs0p = np.exp(-2 * np.sqrt(s * tsp)) fs0m = np.exp(-2 * np.sqrt(s * tsm)) f1p = np.sqrt(s) * f0p f1m = np.sqrt(s) * f0m fs1p = np.sqrt(s) * fs0p fs1m = np.sqrt(s) * fs0m f2p = s * f0p f2m = s * f0m fs2p = s * fs0p fs2m = s * fs0m elif np.abs(signal) == 1: # Time-domain step response # Replace F(m) with F(m-2) f0p = erfc(np.sqrt(tp / time)) f0m = erfc(np.sqrt(tm / time)) fs0p = erfc(np.sqrt(tsp / time)) fs0m = erfc(np.sqrt(tsm / time)) f1p = np.exp(-tp / time) / np.sqrt(np.pi * time) f1m = np.exp(-tm / time) / np.sqrt(np.pi * time) fs1p = np.exp(-tsp / time) / np.sqrt(np.pi * time) fs1m = np.exp(-tsm / time) / np.sqrt(np.pi * time) f2p = f1p * np.sqrt(tp) / time f2m = f1m * np.sqrt(tm) / time fs2p = fs1p * np.sqrt(tsp) / time fs2m = fs1m * np.sqrt(tsm) / time else: # Time-domain impulse response f0p = np.sqrt(tp / (np.pi * time**3)) * np.exp(-tp / time) f0m = np.sqrt(tm / (np.pi * time**3)) * np.exp(-tm / time) fs0p = np.sqrt(tsp / (np.pi * time**3)) * np.exp(-tsp / time) fs0m = np.sqrt(tsm / (np.pi * time**3)) * np.exp(-tsm / time) f1p = (tp / time - 0.5) / np.sqrt(tp) * f0p f1m = (tm / time - 0.5) / np.sqrt(tm) * f0m fs1p = (tsp / time - 0.5) / np.sqrt(tsp) * fs0p fs1m = (tsm / time - 0.5) / np.sqrt(tsm) * fs0m f2p = (tp / time - 1.5) / time * f0p f2m = (tm / time - 1.5) / time * f0m fs2p = (tsp / time - 1.5) / time * fs0p fs2m = (tsm / time - 1.5) / time * fs0m # Pre-allocate arrays gs0m = np.zeros(np.shape(x), dtype=dtype) gs0p = np.zeros(np.shape(x), dtype=dtype) gs1m = np.zeros(np.shape(x), dtype=dtype) gs1p = np.zeros(np.shape(x), dtype=dtype) gs2m = np.zeros(np.shape(x), dtype=dtype) gs2p = np.zeros(np.shape(x), dtype=dtype) g0p = np.zeros(np.shape(x), dtype=dtype) g1m = np.zeros(np.shape(x), dtype=dtype) g1p = np.zeros(np.shape(x), dtype=dtype) g2m = np.zeros(np.shape(x), dtype=dtype) g2p = np.zeros(np.shape(x), dtype=dtype) air = np.zeros(np.shape(f0p), dtype=dtype) if srcrec == 1: # 1. {alpha, beta} # Get indices for singularities izr = rh == 0 # index where rh = 0 iir = np.invert(izr) # invert of izr izh = hm == 0 # index where hm = 0 iih = np.invert(izh) # invert of izh # fab fab = rh**2 * delta - x * y # TM-mode coefficients gs0p = res * aniso * (3 * x * y - rsp**2 * delta) / (4 * np.pi * rsp**5) gs0m = res * aniso * (3 * x * y - rsm**2 * delta) / (4 * np.pi * rsm**5) gs1p[iir] = ( ((3 * x[iir] * y[iir] - rsp[iir]**2 * delta) / rsp[iir]**4 - (x[iir] * y[iir] - fab[iir]) / rh[iir]**4) * np.sqrt(mu_0 * res) / (4 * np.pi)) gs1m[iir] = ( ((3 * x[iir] * y[iir] - rsm[iir]**2 * delta) / rsm[iir]**4 - (x[iir] * y[iir] - fab[iir]) / rh[iir]**4) * np.sqrt(mu_0 * res) / (4 * np.pi)) gs2p[iir] = ((mu_0 * x[iir] * y[iir]) / (4 * np.pi * aniso * rsp[iir]) * (1 / rsp[iir]**2 - 1 / rh[iir]**2)) gs2m[iir] = ((mu_0 * x[iir] * y[iir]) / (4 * np.pi * aniso * rsm[iir]) * (1 / rsm[iir]**2 - 1 / rh[iir]**2)) # TM-mode for numerical singularities rh=0 (hm!=0) gs1p[izr * iih] = -np.sqrt(mu_0 * res) * delta / (4 * np.pi * hsp**2) gs1m[izr * iih] = -np.sqrt(mu_0 * res) * delta / (4 * np.pi * hsm**2) gs2p[izr * iih] = -mu_0 * delta / (8 * np.pi * aniso * hsp) gs2m[izr * iih] = -mu_0 * delta / (8 * np.pi * aniso * hsm) # TE-mode coefficients g0p = res * (3 * fab - rp**2 * delta) / (2 * np.pi * rp**5) g1m[iir] = (np.sqrt(mu_0 * res) * (x[iir] * y[iir] - fab[iir]) / (4 * np.pi * rh[iir]**4)) g1p[iir] = (g1m[iir] + np.sqrt(mu_0 * res) * (3 * fab[iir] - rp[iir]**2 * delta) / (2 * np.pi * rp[iir]**4)) g2p[iir] = mu_0 * fab[iir] / (4 * np.pi * rp[iir]) * (2 / rp[iir]**2 - 1 / rh[iir]**2) g2m[iir] = -mu_0 * fab[iir] / (4 * np.pi * rh[iir]**2 * rm[iir]) # TE-mode for numerical singularities rh=0 (hm!=0) g1m[izr * iih] = np.zeros(np.shape(g1m[izr * iih]), dtype=dtype) g1p[izr * iih] = -np.sqrt(mu_0 * res) * delta / (2 * np.pi * hp**2) g2m[izr * iih] = mu_0 * delta / (8 * np.pi * hm) g2p[izr * iih] = mu_0 * delta / (8 * np.pi * hp) # Bessel functions for airwave def BI(gamH, hp, nr, xim): """Return BI_nr.""" return np.exp(-np.real(gamH) * hp) * ive(nr, xim) def BK(xip, nr): """Return BK_nr.""" return np.exp(-1j * np.imag(xip)) * kve(nr, xip) # Airwave calculation def airwave(s, hp, rp, res, fab, delta): """Return airwave.""" # Parameters zeta = s * mu_0 gamH = np.sqrt(zeta / res) xip = gamH * (rp + hp) / 2 xim = gamH * (rp - hp) / 2 # Bessel functions BI0 = BI(gamH, hp, 0, xim) BI1 = BI(gamH, hp, 1, xim) BI2 = BI(gamH, hp, 2, xim) BK0 = BK(xip, 0) BK1 = BK(xip, 1) # Calculation P1 = (s * mu_0)**(3 / 2) * fab * hp / (4 * np.sqrt(res)) P2 = 4 * BI1 * BK0 - (3 * BI0 - 4 * np.sqrt(res) * BI1 / (np.sqrt(s * mu_0) * (rp + hp)) + BI2) * BK1 P3 = 3 * fab / rp**2 - delta P4 = (s * mu_0 * hp * rp * (BI0 * BK0 - BI1 * BK1) + np.sqrt(res * s * mu_0) * BI0 * BK1 * (rp + hp) + np.sqrt(res * s * mu_0) * BI1 * BK0 * (rp - hp)) return (P1 * P2 - P3 * P4) / (4 * np.pi * rp**3) # Airwave depending on signal if signal is None: # Frequency-domain air = airwave(s, hp, rp, res, fab, delta) elif np.abs(signal) == 1: # Time-domain step response # Solution for step-response air-wave is not analytical, but uses # the Gaver-Stehfest method. K = 16 # Coefficients Dk fn = np.vectorize(np.math.factorial) def coeff_dk(k, K): """Return coefficients Dk for k, K.""" n = np.arange(int((k + 1) / 2), np.min([k, K / 2]) + .5, 1, dtype=int) Dk = n**(K / 2) * fn(2 * n) Dk /= fn(n) * fn(n - 1) * fn(k - n) * fn(2 * n - k) * fn(K / 2 - n) return Dk.sum() * (-1)**(k + K / 2) for k in range(1, K + 1): s = k * np.log(2) / time cair = airwave(s, hp, rp, res, fab, delta) air += coeff_dk(k, K) * cair.real / k else: # Time-domain impulse response thp = mu_0 * hp**2 / (4 * res) trh = mu_0 * rh**2 / (8 * res) P1 = (mu_0**2 * hp * np.exp(-thp / time)) / (res * 32 * np.pi * time**3) P2 = 2 * (delta - (x * y) / rh**2) * ive(1, trh / time) P3 = mu_0 / (2 * res * time) * (rh**2 * delta - x * y) - delta P4 = ive(0, trh / time) - ive(1, trh / time) air = P1 * (P2 - P3 * P4) elif srcrec == 2: # 2. {3, alpha}, {alpha, 3} # TM-mode gs0m = 3 * x * res * aniso**3 * (zrec - zsrc) / (4 * np.pi * rsm**5) gs0p = rev * 3 * x * res * aniso**3 * hp / (4 * np.pi * rsp**5) gs1m = (np.sqrt(mu_0 * res) * 3 * aniso**2 * x * (zrec - zsrc) / (4 * np.pi * rsm**4)) gs1p = rev * np.sqrt( mu_0 * res) * 3 * aniso**2 * x * hp / (4 * np.pi * rsp**4) gs2m = mu_0 * x * aniso * (zrec - zsrc) / (4 * np.pi * rsm**3) gs2p = rev * mu_0 * x * aniso * hp / (4 * np.pi * rsp**3) elif srcrec == 3: # 3. {3, 3} # TM-mode gs0m = res * aniso**3 * (3 * hsm**2 - rsm**2) / (4 * np.pi * rsm**5) gs0p = -res * aniso**3 * (3 * hsp**2 - rsp**2) / (4 * np.pi * rsp**5) gs1m = np.sqrt(mu_0 * res) * aniso**2 * (3 * hsm**2 - rsm**2) / (4 * np.pi * rsm**4) gs1p = -np.sqrt(mu_0 * res) * aniso**2 * (3 * hsp**2 - rsp**2) / ( 4 * np.pi * rsp**4) gs2m = mu_0 * aniso * (hsm**2 - rsm**2) / (4 * np.pi * rsm**3) gs2p = -mu_0 * aniso * (hsp**2 - rsp**2) / (4 * np.pi * rsp**3) # Direct field direct_TM = gs0m * fs0m + gs1m * fs1m + gs2m * fs2m direct_TE = g1m * f1m + g2m * f2m direct = direct_TM + direct_TE # Reflection reflect_TM = gs0p * fs0p + gs1p * fs1p + gs2p * fs2p reflect_TE = g0p * f0p + g1p * f1p + g2p * f2p reflect = reflect_TM + reflect_TE # If switch-on, subtract switch-on from DC value if signal == -1: direct_TM = direct_TM[-1] - direct_TM[:-1] direct_TE = direct_TE[-1] - direct_TE[:-1] direct = direct[-1] - direct[:-1] reflect_TM = reflect_TM[-1] - reflect_TM[:-1] reflect_TE = reflect_TE[-1] - reflect_TE[:-1] reflect = reflect[-1] - reflect[:-1] air = air[-1] - air[:-1] # Return, depending on 'solution' if solution == 'dfs': return direct elif solution == 'dsplit': return direct, reflect, air elif solution == 'dtetm': return direct_TE, direct_TM, reflect_TE, reflect_TM, air else: return direct + reflect + air
def analytic_solution_helper(x, tau, x_0): sqrt_tau = np.sqrt(tau) result = float((1 - tau) * 1 / (x * np.sqrt(tau)) * special.ive(1, 2 * x / x_0 * sqrt_tau) * np.exp(-(1 + tau - 2 * sqrt_tau) * x / x_0)) return result
def _vonmises_pdf(x, mu, kappa): """Calculate vonmises_pdf.""" if kappa <= 0: raise ValueError("Argument 'kappa' must be positive.") pdf = 1 / (2 * np.pi * ive(0, kappa)) * np.exp(np.cos(x - mu) - 1)**kappa return pdf
def BI(gamH, hp, nr, xim): r"""Return BI_nr.""" return np.exp(-np.real(gamH) * hp) * special.ive(nr, xim)
def convolveMRA(field, sigma): if sigma == 0: return field.data n = int(len(field.dimensions[-1].data) / 2) kernel = ive(numpy.arange(-n, n), sigma) return convolve(field.data, kernel, mode='same')
def VerifyBesselIvRatio(self, v, z, rtol): bessel_iv_ratio, v, z = self.evaluate( [tfp.math.bessel_iv_ratio(v, z), v, z]) # Use ive to avoid nans. scipy_ratio = scipy_special.ive(v, z) / scipy_special.ive(v - 1., z) self.assertAllClose(bessel_iv_ratio, scipy_ratio, rtol=rtol)
def compute_params(self): """ Initialize """ check = 1 inc = 0.00000001 c_atzero = check + 1 r0 = self.rmin() r_min = self.rmin() r1 = self.r_1() V = 1 nv = self.N / V e = 0 f = 0 """ Iterate until the condition is satisfied """ while (check > 0.0001): e = e + 1 f = f + 1 check, P, c_atzero = self.PSD(r0, r1) grad_1 = nv * self.p_0 * ((6.28 * r0)**(0.5 * self.d)) * ( (self.d / r0) * sc.jve((0.5 * self.d), r0) + sc.ive( (0.5 * self.d) - 1, r0) - sc.jve((0.5 * self.d) + 1, r0)) grad_2 = nv * (1 - self.p_0) * ((6.28 * r1)**(0.5 * self.d)) * ( (self.d / r1) * sc.jve((0.5 * self.d), r1) + sc.ive( (0.5 * self.d) - 1, r1) - sc.jve((0.5 * self.d) + 1, r1)) grad_norm = (check / r_min) + (r0 * grad_1 / r_min) r0 = r0 + inc * grad_norm r1 = r1 + inc * (grad_2 * r0 / r_min) if self.verbose == 1: if f == 1000: print('iter =', e, ' check=', check) f = 0 r0 = r0 - inc * grad_1 r1 = r1 - inc * grad_2 check, P, c_atzero = self.PSD(r0, r1) """ Summary and figures """ if self.summary == 1: print('---------------------------------------------------') print('N = ', self.N) print('d = ', self.d) print('r0 = ', r0) print('r1 = ', r1) print('p0 = ', self.p_0) print('delta = ', r1 - r0) print('rmin_step =', r_min) print('gain = ', r0 / r_min) print('---------------------------------------------------') plt.figure() plt.plot(P, label='PSD') ze = np.zeros((self.bins, 1)) plt.plot(ze, ':r') plt.title('PSD : N=' + str(self.N) + ' d=' + str(self.d)) plt.legend() #plt.show() return P, r0, r1, self.p_0, r_min
def MRicdf(Ic, Is, interpmethod='cubic'): """ Compute an interpolation function to give the inverse CDF of the modified Rician with a given Ic and Is. Arguments: Ic: float, parameter for M-R Is: float > 0, parameter for M-R Optional argument: interpmethod: keyword passed as 'kind' to interpolate.interp1d Returns: interpolation function f for the inverse CDF of the M-R """ if Is <= 0 or Ic < 0: raise ValueError( "Cannot compute modified Rician CDF with Is<=0 or Ic<0.") # Compute mean and variance of modified Rician, compute CDF by # going 15 sigma to either side (but starting no lower than zero). # Use 1000 points, or about 30 points/sigma. mu = Ic + Is sig = np.sqrt(Is**2 + 2 * Ic * Is) I1 = max(0, mu - 15 * sig) I2 = mu + 15 * sig I = np.linspace(I1, I2, 1000) # Grid spacing. Set I to be offset by dI/2 to give the # trapezoidal rule by direct summation. dI = I[1] - I[0] I += dI / 2 # Modified Rician PDF, and CDF by direct summation of intensities # centered on the bins to be integrated. Enforce normalization at # the end since our integration scheme is off by a part in 1e-6 or # something. #p_I = 1./Is*np.exp(-(Ic + I)/Is)*special.iv(0, 2*np.sqrt(I*Ic)/Is) p_I = 1. / Is * np.exp( (2 * np.sqrt(I * Ic) - (Ic + I)) / Is) * special.ive(0, 2 * np.sqrt(I * Ic) / Is) cdf = np.cumsum(p_I) * dI cdf /= cdf[-1] # The integral is defined with respect to the bin edges. I = np.asarray([0] + list(I + dI / 2)) cdf = np.asarray([0] + list(cdf)) # The interpolation scheme doesn't want duplicate values. Pick # the unique ones, and then return a function to compute the # inverse of the CDF. i = np.unique(cdf, return_index=True)[1] return interpolate.interp1d(cdf[i], I[i], kind=interpmethod)
def Mtil(m, epr, mur, bet, nu, b): def produto(A, B): C = _np.zeros((A.shape[0], B.shape[1], A.shape[2]), dtype=complex) for i in range(A.shape[0]): for j in range(B.shape[1]): for k in range(A.shape[1]): C[i, j, :] = C[i, j, :] + A[i, k, :] * B[k, j, :] return C for i in range( len(b)): # lembrando que length(b) = número de camadas - 1 x = nu[i + 1, :] * b[i] y = nu[i, :] * b[i] Mt = _np.zeros((4, 4, w.shape[0]), dtype=complex) if i < len(b) - 1: D = _np.zeros((4, 4, nu.shape[1]), dtype=complex) z = nu[i + 1, :] * b[i + 1] if not any(z.real < 0): ind = (z.real < 60) A = _scyspe.iv(m, z[ind]) B = _scyspe.kv(m, z[ind]) C = _scyspe.iv(m, x[ind]) E = _scyspe.kv(m, x[ind]) D[0, 0, :] = 1 D[1, 1, ind] = -B * C / (A * E) D[1, 1, ~ind] = -_np.exp(-2 * (z[~ind] - x[~ind])) D[2, 2, :] = 1 D[3, 3, ind] = -B * C / (A * E) D[3, 3, ~ind] = -_np.exp(-2 * (z[~ind] - x[~ind])) Mt[0, 0, :] = -nu[i + 1, :]**2 * b[i] / epr[i + 1, :] * ( epr[i + 1, :] / nu[i + 1, :] * (-_scyspe.kve(m - 1, x) / _scyspe.kve(m, x) - m / x) - epr[i, :] / nu[i, :] * (_scyspe.ive(m - 1, y) / _scyspe.ive(m, y) - m / y)) Mt[0, 1, :] = -nu[i + 1, :]**2 * b[i] / epr[i + 1, :] * ( epr[i + 1, :] / nu[i + 1, :] * (-_scyspe.kve(m - 1, x) / _scyspe.kve(m, x) - m / x) - epr[i, :] / nu[i, :] * (-_scyspe.kve(m - 1, y) / _scyspe.kve(m, y) - m / y)) Mt[1, 0, :] = -nu[i + 1, :]**2 * b[i] / epr[i + 1, :] * ( epr[i + 1, :] / nu[i + 1, :] * (_scyspe.ive(m - 1, x) / _scyspe.ive(m, x) - m / x) - epr[i, :] / nu[i, :] * (_scyspe.ive(m - 1, y) / _scyspe.ive(m, y) - m / y)) Mt[1, 1, :] = -nu[i + 1, :]**2 * b[i] / epr[i + 1, :] * ( epr[i + 1, :] / nu[i + 1, :] * (_scyspe.ive(m - 1, x) / _scyspe.ive(m, x) - m / x) - epr[i, :] / nu[i, :] * (-_scyspe.kve(m - 1, y) / _scyspe.kve(m, y) - m / y)) Mt[0, 2, :] = (nu[i + 1, :]**2 / nu[i, :]**2 - 1) * m / (bet * epr[i + 1, :]) Mt[0, 3, :] = Mt[0, 2, :] Mt[1, 2, :] = Mt[0, 2, :] Mt[1, 3, :] = Mt[0, 2, :] Mt[2, 2, :] = -nu[i + 1, :]**2 * b[i] / mur[i + 1, :] * ( mur[i + 1, :] / nu[i + 1, :] * (-_scyspe.kve(m - 1, x) / _scyspe.kve(m, x) - m / x) - mur[i, :] / nu[i, :] * (_scyspe.ive(m - 1, y) / _scyspe.ive(m, y) - m / y)) Mt[2, 3, :] = -nu[i + 1, :]**2 * b[i] / mur[i + 1, :] * ( mur[i + 1, :] / nu[i + 1, :] * (-_scyspe.kve(m - 1, x) / _scyspe.kve(m, x) - m / x) - mur[i, :] / nu[i, :] * (-_scyspe.kve(m - 1, y) / _scyspe.kve(m, y) - m / y)) Mt[3, 2, :] = -nu[i + 1, :]**2 * b[i] / mur[i + 1, :] * ( mur[i + 1, :] / nu[i + 1, :] * (_scyspe.ive(m - 1, x) / _scyspe.ive(m, x) - m / x) - mur[i, :] / nu[i, :] * (_scyspe.ive(m - 1, y) / _scyspe.ive(m, y) - m / y)) Mt[3, 3, :] = -nu[i + 1, :]**2 * b[i] / mur[i + 1, :] * ( mur[i + 1, :] / nu[i + 1, :] * (_scyspe.ive(m - 1, x) / _scyspe.ive(m, x) - m / x) - mur[i, :] / nu[i, :] * (-_scyspe.kve(m - 1, y) / _scyspe.kve(m, y) - m / y)) Mt[2, 0, :] = (nu[i + 1, :]**2 / nu[i, :]**2 - 1) * m / (bet * mur[i + 1, :]) Mt[2, 1, :] = Mt[2, 0, :] Mt[3, 0, :] = Mt[2, 0, :] Mt[3, 1, :] = Mt[2, 0, :] if len(b) == 1: M = Mt else: if (i == 0): M = produto(D, Mt) elif i < len(b) - 1: M = produto(D, produto(Mt, M)) else: M = produto(Mt, M) return M
def pol(args, p, k, omega): logging.basicConfig(level=args.loglevel or logging.INFO) logger = logging.getLogger(__name__) theta = p['theta'][0] * np.pi / 180. logger.debug("omega guess = %e+%ei \n", omega.real, omega.imag) # epsilon is renormalized: epsilon = epsilon*(v_A^2/c^2*omega^2) epsilon = np.zeros((3, 3), dtype=complex) epsilon += (p['delta'][0] * omega)**2 * np.identity(3) """ Iterate over species """ for m in range(0, int(p['Nsp'][0])): beta_perp = p['beta_perp'][m] beta_para = p['beta_para'][m] beta_ratio = beta_perp / beta_para dens = p['dens'][m] mu = p['mu'][m] q = p['q'][m] kappa = int(p['kappa'][m]) # right now only integer kappa is supported ''' chiX shortcuts for long terms ''' chi = dens**1.5 * q**2 * np.sqrt(mu / beta_para) / (k * np.cos(theta)) chi0 = (beta_ratio - 1.) * mu * dens * q**2 ''' use kappa dispersion relation ''' if (kappa < p['kappa_limit'][0]): ''' first add non-iterative term ''' epsilon[0, 0] += chi0 epsilon[1, 1] += chi0 epsilon[2, 2] += chi0 * np.tan(theta)**2 epsilon[2,2] += 2.*omega**2*(2.*kappa-1.)/(2.*kappa-3.)*dens**2\ *q**2/beta_para/(k*np.cos(theta))**2 epsilon[0, 2] += -chi0 * np.tan(theta) # typo? N = int(p['N'][0]) lab = 0 epsi = np.zeros((3, 3), dtype=complex) while True: add_eps = np.zeros((3, 3), dtype=complex) for n in range(-N, N + 1): # this piece is to avoid unnessary function evaluation if (lab and abs(n) <= N - 1): pass else: eta = beta_ratio * omega - ( beta_ratio - 1.) * n * mu * q # shortcut zh = np.sqrt((2.*kappa+2.)/(2.*kappa-3.))*(omega-n*q*mu)/\ (np.sqrt(beta_para*mu)*k*np.cos(theta))*np.sqrt(dens) jh = k * np.sin(theta) * np.sqrt( (2. * kappa - 3.) * beta_perp / 2. / mu / dens) / q intxx = complex_quadrature(intgrand, zh, jh, kappa, n, 0) intyy = complex_quadrature(intgrand, zh, jh, kappa, n, 1) intxy = complex_quadrature(intgrand, zh, jh, kappa, n, 2) add_eps[0,0] += 4.*np.sqrt(2.)*mu**1.5*dens**2.5*q**4*(kappa-0.5)*((kappa+1.)/(2.*kappa-3.))**1.5\ /(beta_perp*(k*np.sin(theta))**2)/(np.sqrt(beta_para)*k*np.cos(theta))*n**2*eta*intxx add_eps[1, 1] += 2. * np.sqrt(2.) * chi * ( kappa - 0.5) / np.sqrt(2. * kappa - 3.) * ( kappa + 1.)**1.5 * eta * intyy add_eps[2,2] += 4.*np.sqrt(2.)/np.sqrt(mu)*dens**2.5*q**2*(kappa-0.5)*((kappa+1.)/(2.*kappa-3.0))**1.5\ /beta_perp/np.sqrt(beta_para)/(k*np.cos(theta))**3*eta*(omega-n*mu*q)**2*intxx add_eps[0,1] += 4j*mu*dens**2*q**3/np.sqrt(beta_perp*beta_para)/(k**2*np.cos(theta)*np.sin(theta))*\ (kappa-0.5)/(2.*kappa-3.)*(kappa+1.)**1.5*n*eta*intxy add_eps[0,2] += 4.*np.sqrt(2.)*np.sqrt(mu)*dens**2.5*q**3*(kappa-0.5)*((kappa+1)/(2.*kappa-3.))**1.5/\ beta_perp/(k*np.sin(theta))/np.sqrt(beta_para)/(k*np.cos(theta))**2*n*eta*(omega-n*mu*q)*intxx add_eps[1,2] += -4j*dens**2*q**2*(kappa-0.5)/(2.*kappa-3.)*(kappa+1.)**1.5/np.sqrt(beta_perp*beta_para)\ /(k*np.cos(theta))**2*eta*(omega-n*mu*q)*intxy # check if we should increase N, and copy add_eps value to epsi lab, var = check_eps(epsi, add_eps, p['eps_error'][0], lab) if (var): logger.debug("sp[%d], n=%d satisfies constraint!\n", m, N) break epsi += add_eps N += 1 logger.debug("sp[%d], Increase N to =%d!\n", m, N) epsilon += epsi else: '''use bi-maxwellian dispersion''' Lam = (k * np.sin(theta))**2 * beta_perp / (2. * q**2 * mu * dens) # add non-iterative term epsilon[0, 0] += chi0 epsilon[1, 1] += chi0 N = int(p['N'][0]) lab = 0 epsi = np.zeros((3, 3), dtype=complex) while (True): add_eps = np.zeros((3, 3), dtype=complex) for n in range(-N, N + 1): # this piece is to avoid unnessary function evaluation if (lab and abs(n) <= N - 1): pass else: eta = beta_ratio * omega - (beta_ratio - 1.) * n * mu * q zeta = (omega - n * mu * q) * np.sqrt(dens) / ( np.sqrt(beta_para * mu) * k * np.cos(theta)) add_eps[0, 0] += chi * n**2 * sp.ive( n, Lam) / Lam * eta * f.Z(zeta) add_eps[0, 1] += 1j * chi * n * ( f.dIne(n, Lam) - sp.ive(n, Lam)) * eta * f.Z(zeta) add_eps[0,2] += -mu*dens**2*q**3/beta_perp/(k**2*np.sin(theta)*np.cos(theta))*eta*\ n*sp.ive(n,Lam)*f.dp(zeta,0) add_eps[1, 1] += chi * (n**2 * sp.ive(n, Lam) / Lam - 2. * Lam * (f.dIne(n, Lam) - sp.ive(n, Lam)) ) * eta * f.Z(zeta) add_eps[1, 2] += 1j / 2. * dens * q * np.tan( theta) * eta * (f.dIne(n, Lam) - sp.ive(n, Lam)) * f.dp(zeta, 0) add_eps[2,2] += -dens**2*q**2*(omega-n*mu*q)/beta_perp/(k*np.cos(theta))**2*eta*\ sp.ive(n,Lam)*f.dp(zeta,0) # check if we should increase N lab, var = check_eps(epsi, add_eps, p['eps_error'][0], lab) if (var): logger.debug("sp[%d], n=%d satisfies constraint!\n", m, N) break N += 1 epsi += add_eps logger.debug("sp[%d], Increase N to =%d!\n", m, N) epsilon += epsi epsilon[1, 0] = -epsilon[0, 1] epsilon[2, 0] = epsilon[0, 2] epsilon[2, 1] = -epsilon[1, 2] epsilon[0, 0] += -(k * np.cos(theta))**2 epsilon[1, 1] += -k**2 epsilon[2, 2] += -(k * np.sin(theta))**2 epsilon[0, 2] += k**2 * np.sin(theta) * np.cos(theta) epsilon[2, 0] += k**2 * np.sin(theta) * np.cos(theta) ''' calculate determinant ''' disp_det = LA.det(epsilon) / omega**p['exp'][0] # calculate polarization val = np.ones(3, dtype=complex) # eigenvalue vec = np.ones((3, 3), dtype=complex) # eigenvectors val, vec = LA.eig(epsilon) if (abs(omega.real) > 1e-5): pol = 1j * vec[1] / vec[0] * omega.real / abs(omega.real) else: pol = 1j * vec[1] / vec[0] return val, pol
def logive(nu, kappa): return np.log(ive(nu, kappa))
def inference_model_grad(xin, config): # Load parameters n_data = config['N_data'] n_pred = config['N_pred'] c_data = config['c_data'] s_data = config['s_data'] c_2data = config['c_2data'] s_2data = config['s_2data'] mat_kin = config['Kinv'] # not ideal, but this way it's all consistent. idx_psi_p = config['idx_psi_p'] idx_mf_k1 = config['idx_mf_k1'] idx_mf_m1 = config['idx_mf_m1'] k1 = config['k1'] k2 = config['k2'] n_totp = n_data + n_pred # Variable unpacking psi_p = xin[idx_psi_p] mf_k1 = np.exp(xin[idx_mf_k1]) mf_m1 = xin[idx_mf_m1] # Variable reshaping psi_p = psi_p.reshape(n_pred, 1) mf_k1 = mf_k1.reshape(n_totp, 1) mf_m1 = mf_m1.reshape(n_totp, 1) k1 = k1.reshape(1, 1) k2 = k2.reshape(1, 1) # assemble prediction set statistics s_psi_p = np.sin(psi_p) c_psi_p = np.cos(psi_p) s_2psi_p = np.sin(2. * psi_p) c_2psi_p = np.cos(2. * psi_p) c_psi = np.vstack((c_psi_p, c_data)) s_psi = np.vstack((s_psi_p, s_data)) c_2psi = np.vstack((c_2psi_p, c_2data)) s_2psi = np.vstack((s_2psi_p, s_2data)) # Getting mean field moments div_ive_1_0 = ss.ive(1, mf_k1) / ss.ive(0, mf_k1) div_ive_2_0 = ss.ive(2, mf_k1) / ss.ive(0, mf_k1) div_ive_3_0 = ss.ive(3, mf_k1) / ss.ive(0, mf_k1) c_x = div_ive_1_0 * np.cos(mf_m1) s_x = div_ive_1_0 * np.sin(mf_m1) c_2x = div_ive_2_0 * np.cos(2. * mf_m1) s_2x = div_ive_2_0 * np.sin(2. * mf_m1) cc_x = 0.5 * (1 + c_2x) ss_x = 0.5 * (1 - c_2x) cs_x = 0.5 * s_2x # Building inverse sections mat_kin_cc = mat_kin[0:n_totp, 0:n_totp] mat_kin_ss = mat_kin[n_totp:, n_totp:] mat_kin_cs = mat_kin[0:n_totp, n_totp:] diag_mat_kin_cc = np.diag(mat_kin[0:n_totp, 0:n_totp]).reshape(n_totp, 1) diag_mat_kin_ss = np.diag(mat_kin[n_totp:, n_totp:]).reshape(n_totp, 1) diag_mat_kin_cs = np.diag(mat_kin[0:n_totp, n_totp:]).reshape(n_totp, 1) np.fill_diagonal(mat_kin_cc, 0.) np.fill_diagonal(mat_kin_ss, 0.) np.fill_diagonal(mat_kin_cs, 0.) # Gradient assembly point # ---------------------------------------------------- # Prior dpri_psi_p = 0. dpri_c_x = - (np.dot(mat_kin_cc, c_x) + np.dot(mat_kin_cs, s_x)) dpri_s_x = - (np.dot(mat_kin_ss, s_x) + np.dot(mat_kin_cs.T, c_x)) dpri_cc_x = - 0.5 * diag_mat_kin_cc dpri_ss_x = - 0.5 * diag_mat_kin_ss dpri_cs_x = - diag_mat_kin_cs # Likelihood ds_psi_psi_p = + np.cos(psi_p) dc_psi_psi_p = - np.sin(psi_p) ds_2psi_psi_p = + 2. * np.cos(2. * psi_p) dc_2psi_psi_p = - 2. * np.sin(2. * psi_p) dlik_s_psi = k1 * s_x[0:n_pred] dlik_c_psi = k1 * c_x[0:n_pred] dlik_s_2psi = k2 * s_2x[0:n_pred] dlik_c_2psi = k2 * c_2x[0:n_pred] dlik_psi_p = (dlik_s_psi * ds_psi_psi_p + dlik_c_psi * dc_psi_psi_p + dlik_s_2psi * ds_2psi_psi_p + dlik_c_2psi * dc_2psi_psi_p) dlik_c_x = +k1 * c_psi dlik_s_x = +k1 * s_psi dlik_cc_x = +k2 * c_2psi dlik_ss_x = -k2 * c_2psi dlik_cs_x = +2.0 * k2 * s_2psi # Mean field gradients (along with entropy) dc_x_mf_k1 = np.cos(mf_m1) * (0.5 * (1. + div_ive_2_0) - div_ive_1_0 ** 2) ds_x_mf_k1 = np.sin(mf_m1) * (0.5 * (1. + div_ive_2_0) - div_ive_1_0 ** 2) dcc_x_mf_k1 = +0.5 * np.cos(2. * mf_m1) * (0.5 * (div_ive_1_0 + div_ive_3_0) - div_ive_1_0 * div_ive_2_0) dss_x_mf_k1 = -0.5 * np.cos(2. * mf_m1) * (0.5 * (div_ive_1_0 + div_ive_3_0) - div_ive_1_0 * div_ive_2_0) dcs_x_mf_k1 = +0.5 * np.sin(2. * mf_m1) * (0.5 * (div_ive_1_0 + div_ive_3_0) - div_ive_1_0 * div_ive_2_0) dent_mf_k1 = - 0.5 * mf_k1 * (1. + div_ive_2_0) + mf_k1 * div_ive_1_0 ** 2 dc_x_mf_m1 = - np.sin(mf_m1) * div_ive_1_0 ds_x_mf_m1 = + np.cos(mf_m1) * div_ive_1_0 dcc_x_mf_m1 = - np.sin(2. * mf_m1) * div_ive_2_0 dss_x_mf_m1 = + np.sin(2. * mf_m1) * div_ive_2_0 dcs_x_mf_m1 = + np.cos(2. * mf_m1) * div_ive_2_0 dent_mf_m1 = 0. dmf_k1 = (dpri_c_x + dlik_c_x) * dc_x_mf_k1 + (dpri_s_x + dlik_s_x) * ds_x_mf_k1 + \ (dpri_cc_x + dlik_cc_x) * dcc_x_mf_k1 + (dpri_ss_x + dlik_ss_x) * dss_x_mf_k1 + \ (dpri_cs_x + dlik_cs_x) * dcs_x_mf_k1 + dent_mf_k1 dmf_m1 = (dpri_c_x + dlik_c_x) * dc_x_mf_m1 + (dpri_s_x + dlik_s_x) * ds_x_mf_m1 + \ (dpri_cc_x + dlik_cc_x) * dcc_x_mf_m1 + (dpri_ss_x + dlik_ss_x) * dss_x_mf_m1 + \ (dpri_cs_x + dlik_cs_x) * dcs_x_mf_m1 + dent_mf_m1 # Final gradient assembly dpsi_p = dlik_psi_p + dpri_psi_p # Positivy transformation dlog_mf_k1 = dmf_k1 * mf_k1 grad = np.vstack((dpsi_p, dlog_mf_k1, dmf_m1)) return - grad.flatten()
def inference_model_obj(xin, config): # Load parameters n_data = config['N_data'] n_pred = config['N_pred'] c_data = config['c_data'] s_data = config['s_data'] c_2data = config['c_2data'] s_2data = config['s_2data'] mat_kin = config['Kinv'] # not ideal, but this way it's all consistent. idx_psi_p = config['idx_psi_p'] idx_mf_k1 = config['idx_mf_k1'] idx_mf_m1 = config['idx_mf_m1'] k1 = config['k1'] k2 = config['k2'] n_totp = n_data + n_pred # Variable unpacking psi_p = xin[idx_psi_p] mf_k1 = np.exp(xin[idx_mf_k1]) mf_m1 = xin[idx_mf_m1] # Variable reshaping psi_p = psi_p.reshape(n_pred, 1) mf_k1 = mf_k1.reshape(n_totp, 1) mf_m1 = mf_m1.reshape(n_totp, 1) k1 = k1.reshape(1, 1) k2 = k2.reshape(1, 1) # assemble prediction set statistics s_psi_p = np.sin(psi_p) c_psi_p = np.cos(psi_p) s_2psi_p = np.sin(2. * psi_p) c_2psi_p = np.cos(2. * psi_p) c_psi = np.vstack((c_psi_p, c_data)) s_psi = np.vstack((s_psi_p, s_data)) c_2psi = np.vstack((c_2psi_p, c_2data)) s_2psi = np.vstack((s_2psi_p, s_2data)) # Getting mean field moments div_ive_1_0 = ss.ive(1, mf_k1) / ss.ive(0, mf_k1) div_ive_2_0 = ss.ive(2, mf_k1) / ss.ive(0, mf_k1) c_x = div_ive_1_0 * np.cos(mf_m1) s_x = div_ive_1_0 * np.sin(mf_m1) c_2x = div_ive_2_0 * np.cos(2. * mf_m1) s_2x = div_ive_2_0 * np.sin(2. * mf_m1) cc_x = 0.5 * (1 + c_2x) ss_x = 0.5 * (1 - c_2x) cs_x = 0.5 * s_2x # Building inverse sections mat_kin_cc = mat_kin[0:n_totp, 0:n_totp] mat_kin_ss = mat_kin[n_totp:, n_totp:] mat_kin_cs = mat_kin[0:n_totp, n_totp:] diag_mat_kin_cc = np.diag(mat_kin[0:n_totp, 0:n_totp]).reshape(n_totp, 1) diag_mat_kin_ss = np.diag(mat_kin[n_totp:, n_totp:]).reshape(n_totp, 1) diag_mat_kin_cs = np.diag(mat_kin[0:n_totp, n_totp:]).reshape(n_totp, 1) np.fill_diagonal(mat_kin_cc, 0.) np.fill_diagonal(mat_kin_ss, 0.) np.fill_diagonal(mat_kin_cs, 0.) # Free energy assembly point # ---------------------------------------------------- prior = - (la.qform(c_x, mat_kin_cs, s_x) + np.dot(diag_mat_kin_cs.T, cs_x) + 0.5 * (la.qform(c_x, mat_kin_cc, c_x) + np.dot(diag_mat_kin_cc.T, cc_x) + la.qform(s_x, mat_kin_ss, s_x) + np.dot(diag_mat_kin_ss.T, ss_x))) likelihood = k1 * (np.dot(c_psi.T, c_x) + np.dot(s_psi.T, s_x)) - n_totp * (np.log(ss.ive(0, k1)) + k1) +\ k2 * (np.dot(c_2psi.T, cc_x - ss_x) + np.dot(s_2psi.T, 2 * cs_x)) - n_totp * (np.log(ss.ive(0, k2)) + k2) entropy = np.sum(np.log(ss.ive(0, mf_k1)) + mf_k1 - mf_k1 * ss.ive(1, mf_k1) / ss.ive(0, mf_k1)) energy = likelihood + prior + entropy return - energy.flatten()
def compute_log_partition(self, az, bz, y): b = np.absolute(bz) I0 = ive(0, b * y) logZ = np.sum(-0.5 * az * (y**2) + np.log(2 * np.pi * y * ive(0, b * y)) + b * y) return logZ
def vonmises_coefficient(k,m): return ive(m,k)/ive(0,k)
def convolveMRA(field, sigma): if sigma==0: return field.data n = int(len(field.dimensions[-1].data)/2) kernel = ive(numpy.arange(-n, n), sigma) return convolve(field.data, kernel, mode='same')
def dIne(n,a): return 0.5*(sp.ive(n-1,a)+sp.ive(n+1,a))
def VerifyBesselIve(self, v, z, rtol, atol=1e-7): bessel_ive, v, z = self.evaluate([tfp.math.bessel_ive(v, z), v, z]) scipy_ive = scipy_special.ive(v, z) self.assertAllClose(bessel_ive, scipy_ive, rtol=rtol, atol=atol)
def dive(n,a,i): a = float(a) # No perpendicular component if a ==0: if i == 1: fz = 0.5*(sp.ive(n-1,a)+sp.ive(n+1,a))-sp.ive(n,a) elif i == 2: fz = 0.25*sp.ive(n-2,a)-sp.ive(n-1,a)+1.5*sp.ive(n,a)\ -sp.ive(n+1,a)+0.25*sp.ive(n+2,a) else: sys.exit("Error:i should be 1 or 2 for dive function!") # with perpendicular component else: if i == 1: fz = (n/a-1)*sp.ive(n,a)+sp.ive(n+1,a) elif i == 2: fz = ((n**2-n)/a**2-2*n/a+1.)*sp.ive(n,a)+\ ((2*n+1.0)/a-2)*sp.ive(n+1,a)+sp.ive(n+2,a) else: sys.exit("Error:i should be 1 or 2 for dive function!") return fz
def k2w_es3d( kxs, kzs, species, params, isMag=None, J=8, N=10, check_convergence=True, convergence_thresh=0.975, sort="real", dry_run=False, ): """ Compute electrostatic dispersion relation for a magnetized Vlasov-Poisson system assuming the background magnetic field along `z` and the wavevector `k` can have components along `x` and `z`, i.e., the perpendicular and parallel directions. The basic algorithm follows [1]. The Z function is approximated by a J-pole Pade expansion and the bi-Maxwellian distribution is approximated by a truncated summation of Bessel functions. This way, a linear system is generated that can be solved for complex frequencies as eigenvalues of the equivalent matrix. [1]:https://iopscience.iop.org/article/10.1088/1009-0630/18/2/01/pdf Args: kxs (np.ndarray): Wavevector component values along `x`. kzs (np.ndarray): Wavevector component values along `z`. species (np.ndarray): A list of parameters of each plasma species. `species[s]` are the parameters of the `s`th species, including `q, m, n, v0x, v0z, p0x, p0z`. params (dict): A dictionary of relevant parameters. Here, the used ones are `epsilon0` and `Bz`. isMag (list or None): A list of booleans to indicate wether each species is magnetized. If not set, all species are assumed to be magnetized. J (int): Order of Pade approximation. One of (`8`, `12`). N (int): Highest order of cylctron harmonic to include in the Bessel expansion of the bi-Maxwellian distribution. If `check_convergence` is set to True, `N` will be increased until the expansion coefficients add up to greater than a threshold value set by `convergence_thresh`. check_convergence (bool): See option `N`. Default is True. convergence_thresh (float): See option `N`. Default is 0.975. sort (str): Order for sorting computed frequencies. Default is "real". sort (str): `'real'` or `'imag'` or `'none'`. Order to sort results. Returns: ws (np.ndarray or list): Computed frequencies in a list. `ws[ik]` is the solution for the `ik`th wavevector. The result is packed as a `np.ndarray` if the `N` values used for all `k` are the same. """ q, m, n, vx, vz, px, pz = np.rollaxis(np.array(species), axis=1) eps0 = params['epsilon0'] Bz = params['Bz'] S = len(q) # number of species lamDz = np.sqrt(eps0 * pz / (n * q)**2) vtz = np.sqrt(2. * pz / n / m) vtx = np.sqrt(2. * px / n / m) wc = q * Bz / m if isMag is None: isMag = [True] * S assert (len(isMag) == S) bz, cz = bzs[J], czs[J] Tz_Tx = (vtz / vtx)**2 rc = vtx / np.sqrt(2) / np.abs(wc) ks = np.sqrt(kzs**2 + kxs**2) nk = len(ks) ws = [] Ns = np.zeros((nk, ), dtype=np.int32) if check_convergence: if np.any(isMag): for ik in range(nk): Nmax = N kz = kzs[ik] kp = kxs[ik] kp_rc2m = ((kp * rc[isMag])**2).max() found = False while (not found): bessSum = ive(range(-Nmax, Nmax + 1), kp_rc2m).sum() if bessSum < convergence_thresh: Nmax = Nmax + 1 else: found = True if ik == len(ks) - 1: logging.debug( "(kp*rc)^2 {}, N {}, bessSum {}".format( kp_rc2m, Nmax, bessSum)) Ns[ik] = Nmax logging.debug("Ns {}".format(Ns)) print('Ns', Ns) if dry_run: return for ik, k in enumerate(ks): kz = kzs[ik] kp = kxs[ik] N4k = Ns[ik] # the number of terms to keep for k SNJ = S * (2 * N4k + 1) * J M = np.zeros((SNJ, SNJ), dtype=np.complex128) B = np.zeros([SNJ], dtype=np.complex128) C = np.zeros([SNJ], dtype=np.complex128) m = 0 for s in range(S): if isMag[s]: for n in range(-N4k, N4k + 1): bessel = ive(n, (kp * rc[s])**2) # modified Bessel function for j in range(J): B[m] = bessel * bz[j] \ * (cz[j] * kz * vtz[s] + n * wc[s] * Tz_Tx[s]) \ / (lamDz[s] * k)**2 C[m] = kz * vz[s] + kp * vx[s] + n * wc[s] \ + cz[j] * kz * vtz[s] m += 1 else: bessel = 1. / (2. * N4k + 1.) for n in range(-N4k, N4k + 1): for j in range(J): B[m] = bessel * bz[j] * (cz[j] * k * vtz[s]) \ / (lamDz[s] * k)**2 C[m] = kz * vz[s] + kp * vx[s] + cz[j] * k * vtz[s] m += 1 for m in range(SNJ): M[m, :] = -B[m] M[m, m] += C[m] w = scipy.linalg.eigvals(M) sort_idx = slice(None) if sort in ["imag"]: sort_idx = np.argsort(w.imag + 1j * w.real) elif sort in ["real"]: sort_idx = np.argsort(w) elif sort != 'none': raise ValueError('`sort` value {} not recognized'.format(sort)) ws.append(w[sort_idx]) if Ns.min() == Ns.max(): # if different k has different N, the size of ws are different return np.array(ws) else: return ws
def U(self, r): C = np.sqrt(2.0 * np.pi) / self.r_0 / 2.0 x = r**2 / 4.0 / self.r_0**2 # ive is bessel function of # imaginary argument * decaying exponent return special.ive(0, x) * C
def cp_log(p, kappa): p = float(p) cp = (p / 2 - 1) * np.log(kappa) cp += -(p / 2) * np.log(2 * pi) - np.log(ive(p / 2 - 1, kappa)) - kappa return cp
def log_norm(cls, kappa, D): kappa = np.clip(kappa, 1e-10, np.inf) return ( (D / 2) * np.log(2 * np.pi) + np.log(ive(D / 2 - 1, kappa)) + np.abs(kappa) - (D / 2 - 1) * np.log(kappa) )
def BI(gamH, hp, nr, xim): """Return BI_nr.""" return np.exp(-np.real(gamH) * hp) * ive(nr, xim)
def ratio(self, l): """Compute the ratio I_{l+1/2}(alpha) / I_{l-1/2}(alpha)""" return ive(l + 0.5, self.alpha) / ive(l - 0.5, self.alpha)
def Mtil(m, epr, mur, bet, nu, b): def produto(A,B): C = _np.zeros((A.shape[0],B.shape[1],A.shape[2]),dtype=complex) for i in range(A.shape[0]): for j in range(B.shape[1]): for k in range(A.shape[1]): C[i,j,:] = C[i,j,:] + A[i,k,:]*B[k,j,:] return C for i in range(len(b)): # lembrando que length(b) = número de camadas - 1 x = nu[i+1,:] * b[i] y = nu[i ,:] * b[i] Mt = _np.zeros((4,4,w.shape[0]),dtype=complex) if i<len(b)-1: D = _np.zeros((4,4,nu.shape[1]),dtype=complex) z = nu[i+1,:]*b[i+1] if not any(z.real<0): ind = (z.real<60) A = _scyspe.iv(m,z[ind]) B = _scyspe.kv(m,z[ind]) C = _scyspe.iv(m,x[ind]) E = _scyspe.kv(m,x[ind]) D[0,0,:] = 1 D[1,1,ind] = - B*C/(A*E) D[1,1,~ind] = - _np.exp(-2*(z[~ind]-x[~ind])) D[2,2,:] = 1 D[3,3,ind] = - B*C/(A*E) D[3,3,~ind] = - _np.exp(-2*(z[~ind]-x[~ind])) Mt[0,0,:] = -nu[i+1,:]**2*b[i]/epr[i+1,:]*( epr[i+1,:]/nu[i+1,:]*(-_scyspe.kve(m-1,x)/_scyspe.kve(m,x) - m/x) - epr[i,:]/nu[i,:] *( _scyspe.ive(m-1,y)/_scyspe.ive(m,y) - m/y)) Mt[0,1,:] = -nu[i+1,:]**2*b[i]/epr[i+1,:]*( epr[i+1,:]/nu[i+1,:]*(-_scyspe.kve(m-1,x)/_scyspe.kve(m,x) - m/x) - epr[i,:]/nu[i,:] *(-_scyspe.kve(m-1,y)/_scyspe.kve(m,y) - m/y)) Mt[1,0,:] = -nu[i+1,:]**2*b[i]/epr[i+1,:]*( epr[i+1,:]/nu[i+1,:]*( _scyspe.ive(m-1,x)/_scyspe.ive(m,x) - m/x) - epr[i,:]/nu[i,:] *( _scyspe.ive(m-1,y)/_scyspe.ive(m,y) - m/y)) Mt[1,1,:] = -nu[i+1,:]**2*b[i]/epr[i+1,:]*( epr[i+1,:]/nu[i+1,:]*( _scyspe.ive(m-1,x)/_scyspe.ive(m,x) - m/x) - epr[i,:]/nu[i,:] *(-_scyspe.kve(m-1,y)/_scyspe.kve(m,y) - m/y)) Mt[0,2,:] = (nu[i+1,:]**2/nu[i,:]**2 - 1)*m/(bet*epr[i+1,:]) Mt[0,3,:] = Mt[0,2,:] Mt[1,2,:] = Mt[0,2,:] Mt[1,3,:] = Mt[0,2,:] Mt[2,2,:] = -nu[i+1,:]**2*b[i]/mur[i+1,:]*( mur[i+1,:]/nu[i+1,:]*(-_scyspe.kve(m-1,x)/_scyspe.kve(m,x) - m/x) - mur[i,:]/nu[i,:] *( _scyspe.ive(m-1,y)/_scyspe.ive(m,y) - m/y)) Mt[2,3,:] = -nu[i+1,:]**2*b[i]/mur[i+1,:]*( mur[i+1,:]/nu[i+1,:]*(-_scyspe.kve(m-1,x)/_scyspe.kve(m,x) - m/x) - mur[i,:]/nu[i,:] *(-_scyspe.kve(m-1,y)/_scyspe.kve(m,y) - m/y)) Mt[3,2,:] = -nu[i+1,:]**2*b[i]/mur[i+1,:]*( mur[i+1,:]/nu[i+1,:]*( _scyspe.ive(m-1,x)/_scyspe.ive(m,x) - m/x) - mur[i,:]/nu[i,:] *( _scyspe.ive(m-1,y)/_scyspe.ive(m,y) - m/y)) Mt[3,3,:] = -nu[i+1,:]**2*b[i]/mur[i+1,:]*( mur[i+1,:]/nu[i+1,:]*( _scyspe.ive(m-1,x)/_scyspe.ive(m,x) - m/x) - mur[i,:]/nu[i,:] *(-_scyspe.kve(m-1,y)/_scyspe.kve(m,y) - m/y)) Mt[2,0,:] = (nu[i+1,:]**2/nu[i,:]**2 - 1)*m/(bet*mur[i+1,:]) Mt[2,1,:] = Mt[2,0,:] Mt[3,0,:] = Mt[2,0,:] Mt[3,1,:] = Mt[2,0,:] if len(b) == 1: M = Mt else: if (i ==0): M = produto(D,Mt) elif i < len(b)-1: M = produto(D,produto(Mt,M)) else: M = produto(Mt,M) return M
def f_scaled(xi_b, xi_y): b = sz_eff * xi_b y = b / az + xi_y / np.sqrt(az) coef = 2 * np.pi / np.sqrt(u_eff) bz = complex2array(np.array(b)) return coef * relu(b) * relu(y) * ive(0, b * y) * f(bz, y)
def U(self, r): C = np.sqrt(2.0 * np.pi) / self.r_0 / 2.0; x = r**2 / 4.0 / self.r_0**2 # ive is bessel function of # imaginary argument * decaying exponent return special.ive(0, x) * C
def magnetic_field_time_deriv_magnetic_dipole(t, xy, sigma=1.0, mu=mu_0, moment=1.0): """Magnetic field time derivative due to step off vertical dipole at the surface Parameters ---------- t : (n_t) numpy.ndarray times (s) xy : (n_locs, 2) numpy.ndarray surface field locations (m) sigma : float, optional conductivity mu : float, optional magnetic permeability moment : float, optional moment of the dipole Returns ------- dh_dt : (n_t, n_locs, 3) numpy.ndarray The magnetic field at the observation locations and times. Notes ----- Matches the negative of equation 4.70 of Ward and Hohmann 1988, for the vertical component (due to the difference in coordinate sign conventionn used here). .. math:: \\frac{\\partial h_z}{\\partial t} = \\frac{m}{2 \\pi \\mu \\sigma \\rho^5}\\left[ 9\\mathrm{erf}(\\theta \\rho) - \\frac{2\\theta\\rho}{\\sqrt{\\pi}}\\left( 9 + 6\\theta^2\\rho^2 + 4\\theta^4\\rho^4\\right) e^{-\\theta^2\\rho^2} \\right] Also matches equation 4.74 for the horizontal components .. math:: \\frac{\\partial h_\\rho}{\\partial t} = -\\frac{m \\theta^2}{2 \\pi \\rho t}e^{-\\theta^2\\rho^2/2} \\left[ (1 +\\theta^2 \\rho^2) I_0 \\left( \\frac{\\theta^2\\rho^2}{2} \\right) - \\left( 2 + \\theta^2\\rho^2 + \\frac{4}{\\theta^2\\rho^2}\\right)I_1\\left(\\frac{\\theta^2\\rho^2}{2}\\right) \\right] Examples -------- Reproducing the time derivate parts of Figure 4.4 and 4.5 from Ward and Hohmann 1988 >>> import numpy as np >>> import matplotlib.pyplot as plt >>> from geoana.em.tdem import magnetic_field_time_deriv_magnetic_dipole Calculate the field at the time given, 100 m along the x-axis, >>> times = np.logspace(-6, 0, 200) >>> xy = np.array([[100, 0, 0]]) >>> dh_dt = magnetic_field_time_deriv_magnetic_dipole(times, xy, sigma=1E-2) Match the vertical magnetic field plot >>> plt.loglog(times*1E3, dh_dt[:,0, 2], c='C0', label=r'$\\frac{\\partial h_z}{\\partial t}$') >>> plt.loglog(times*1E3, -dh_dt[:,0, 2], '--', c='C0') >>> plt.loglog(times*1E3, dh_dt[:,0, 0], c='C1', label=r'$\\frac{\\partial h_x}{\\partial t}$') >>> plt.loglog(times*1E3, -dh_dt[:,0, 0], '--', c='C1') >>> plt.xlabel('time (ms)') >>> plt.ylabel(r'$\\frac{\\partial h}{\\partial t}$ (A/(m s))') >>> plt.legend() >>> plt.show() """ r = np.linalg.norm(xy[:, :2], axis=-1) x = xy[:, 0] y = xy[:, 1] tr = theta(t, sigma, mu)[:, None] * r dhz_dt = 1 / (r**3 * t[:, None]) * ( 9 / (2 * tr**2) * erf(tr) - (4 * tr**3 + 6 * tr + 9 / tr) / np.sqrt(np.pi) * np.exp(-tr**2)) # iv(k, v) = ive(k, v) * exp(abs(arg)) dhr_dt = -2 * tr**2 / (r**3 * t[:, None]) * ( (1 + tr**2) * ive(0, tr**2 / 2) - (2 + tr**2 + 4 / tr**2) * ive(1, tr**2 / 2)) angle = np.arctan2(y, x) dhx_dt = np.cos(angle) * dhr_dt dhy_dt = np.sin(angle) * dhr_dt return moment / (4 * np.pi) * np.stack((dhx_dt, dhy_dt, dhz_dt), axis=-1)