def sound_hard_circle(k, rad, plot_grid): x = np.vstack((plot_grid[0].ravel(), plot_grid[1].ravel())) points = x fem_xx = points[0, :] fem_xy = points[1, :] r = np.sqrt(fem_xx * fem_xx + fem_xy * fem_xy) theta = np.arctan2(fem_xy, fem_xx) npts = np.size(fem_xx, 0) a = rad n_terms = np.int(30 + (k * a)**1.01) k0 = k Nx = plot_grid.shape[1] Ny = plot_grid.shape[2] u_inc = np.exp(1j * k0 * fem_xx) n_int = np.where(r < a) u_inc[n_int] = 0.0 u_plot = u_inc.reshape(Nx, Ny) u_sc = np.zeros((npts), dtype=np.complex128) for n in range(-n_terms, n_terms): bessel_deriv = jv(n - 1, k0 * a) - n / (k0 * a) * jv(n, k0 * a) hankel_deriv = n / (k0 * a) * hankel1(n, k0 * a) - hankel1( n + 1, k0 * a) u_sc += -(1j)**(n) * (bessel_deriv/hankel_deriv) * hankel1(n, k0*r) * \ np.exp(1j*n*theta) u_sc[n_int] = 0.0 u_scat = u_sc.reshape(Nx, Ny) u_tot = u_scat + u_plot return u_tot
def sound_soft_circle(k, rad, plot_grid): # from pylab import find from scipy.special import jv, hankel1 import numpy as np x = np.vstack((plot_grid[0].ravel(), plot_grid[1].ravel())) points = x fem_xx = points[0, :] fem_xy = points[1, :] r = np.sqrt(fem_xx * fem_xx + fem_xy * fem_xy) theta = np.arctan2(fem_xy, fem_xx) npts = np.size(fem_xx, 0) a = rad n_terms = np.int(30 + (k * a)**1.01) k0 = k Nx = plot_grid.shape[1] Ny = plot_grid.shape[2] u_inc = np.exp(1j * k0 * fem_xx) n_int = np.where(r < a) u_inc[n_int] = 0.0 u_plot = u_inc.reshape(Nx, Ny) u_sc = np.zeros((npts), dtype=np.complex128) for n in range(-n_terms, n_terms): u_sc += -(1j)**(n) * (jv(n, k0*a)/hankel1(n, k0*a)) * \ hankel1(n, k0*r) * np.exp(1j*n*theta) u_sc[n_int] = 0.0 u_scat = u_sc.reshape(Nx, Ny) u_tot = u_scat + u_plot return u_tot
def em_sca_coef_my(self): """ calculates self.an and self.bn scattering coefficients a[k], b[k] correspond to order k+1 """ m = np.sqrt(self.eps_t) * np.sqrt( self.mu_t) / (np.sqrt(self.eps_m) * np.sqrt(self.mu_m)) x = self.k * self.a nmax = int(round(x + 4 * x**(1. / 3.) + 2.)) self.nmax = np.round(max(nmax, np.abs(m * x)) + 16) besx = np.zeros(self.nmax, dtype=np.complex) dbesx = np.zeros(self.nmax, dtype=np.complex) dbesx2 = np.zeros(self.nmax, dtype=np.complex) hanx = np.zeros(self.nmax, dtype=np.complex) dhanx = np.zeros(self.nmax, dtype=np.complex) besmx_e = np.zeros(self.nmax, dtype=np.complex) dbesmx_e = np.zeros(self.nmax, dtype=np.complex) besmx_m = np.zeros(self.nmax, dtype=np.complex) dbesmx_m = np.zeros(self.nmax, dtype=np.complex) sqx = np.sqrt(0.5 * pi / x) dsqx = -0.5 * np.sqrt(0.5 * pi / x**3) sqmx = np.sqrt(0.5 * pi / (m * x)) dsqmx = -0.5 * np.sqrt(0.5 * pi / (m * x)**3) for n in range(1, self.nmax + 1): besx[n - 1] = sp_spec.spherical_jn(n, x) dbesx[n - 1] = sp_spec.spherical_jn(n, x, True) hanx[n - 1] = sqx * sp_spec.hankel1(n + 0.5, x) # sph. hankel 1st kind dhanx[n - 1] = sqx * sp_spec.h1vp(n + 0.5, x) + dsqx * sp_spec.hankel1( n + 0.5, x) # d. sph. hankel 1st n1 = np.sqrt(n * (n + 1) * self.eps_t / self.eps_r + 0.25) - 0.5 besmx_e[n - 1] = sqmx * sp_spec.jv(n1 + 0.5, m * x) dbesmx_e[n - 1] = sqmx * sp_spec.jvp( n1 + 0.5, m * x) + dsqmx * sp_spec.jv(n1 + 0.5, m * x) n2 = np.sqrt(n * (n + 1) * self.mu_t / self.mu_r + 0.25) - 0.5 besmx_m[n - 1] = sqmx * sp_spec.jv(n2 + 0.5, m * x) dbesmx_m[n - 1] = sqmx * sp_spec.jvp( n2 + 0.5, m * x) + dsqmx * sp_spec.jv(n2 + 0.5, m * x) self.an = ((self.mu_m * m**2 * (besx + x * dbesx) * besmx_e - self.mu_t * besx * (besmx_e + m * x * dbesmx_e)) / (self.mu_m * m**2 * (hanx + x * dhanx) * besmx_e - self.mu_t * hanx * (besmx_e + m * x * dbesmx_e))) self.bn = ((self.mu_t * (besx + x * dbesx) * besmx_m - self.mu_m * besx * (besmx_m + m * x * dbesmx_m)) / (self.mu_t * (hanx + x * dhanx) * besmx_m - self.mu_m * hanx * (besmx_m + m * x * dbesmx_m)))
def rootsAnnSec(m, rMin, rMax, aMin, aMax): f0 = lambda k: ivp(m, η * k) * hankel1(m, k) / η + iv(m, η * k) * h1vp( m, k) f1 = (lambda k: ivp(m, η * k, 2) * hankel1(m, k) + c * ivp(m, η * k) * h1vp(m, k) + iv(m, η * k) * h1vp(m, k, 2)) A = AnnulusSector(center=0.0, radii=(rMin, rMax), phiRange=(aMin, aMax)) z = A.roots(f0, df=f1) return z.roots
def sears_fun(kg): """ Produces Sears function """ S12 = 2. / np.pi / kg / (scsp.hankel1(0, kg) + 1.j * scsp.hankel1(1, kg)) S = np.exp(-1.j * kg) * S12.conj() return S
def GaussianPulseDR(epsilon, Bx, c0, zm, zs, LOG='no'): ''' Analytical Propgation of a gaussion pulse near a rigid boundary. epsilon : amplitude of the gaussian Bx : width of the gaussian c0 : celerity of wave zm : location of the microphone zs : location of the source LOG : if LOG=='log', display complementary informations ''' ext = 10 Nfreq = 2**12 Npadd = 2**14 B = np.sqrt(Bx**2/np.log(2)) k0 = np.sqrt(2)/B fmin = 0.00001 fmax = k0*c0/(2*np.pi) r1 = abs(zm-zs) r2 = abs(zm+zs) # Axes k = np.linspace(2*np.pi*fmin/c0, ext*k0, Nfreq) f = np.linspace(fmin, ext*fmax, Nfreq) df = f[2] - f[1] wtime = np.linspace(0, 1/df, Npadd) # Puissance de la source % omega Sw = 1j*k*np.pi*epsilon*B**2*np.exp(-k**2*B**2/4.)/c0 # Pression dans le domaine freq. Pdw = -1j*Sw*hankel1(0, k*r1)/4. Prw = -1j*Sw*hankel1(0, k*r2)/4. Ai = fmax*Nfreq/(2*np.pi) Pdt = Ai*ifft(Pdw, Npadd)[::-1] Prt = Ai*ifft(Prw, Npadd)[::-1] if LOG == 'log': print('Max. frequency : ' + repr(fmax)) pl.figure('Source Strenght') pl.subplot(311) pl.plot(f, abs(Sw), 'k') pl.ylabel('Strength $S_w$') pl.subplot(312) pl.plot(f, abs(Pdw), 'k', label='Direct') pl.plot(f, abs(Prw), color='0.5', label='Reflected') pl.legend() pl.ylabel(r'Pressure $\tilde{p}(r,w)$') pl.subplot(313) pl.plot(wtime, Pdt.real/Pdt.real.max(), color='0.8', label='Direct') pl.plot(wtime, Prt.real/Prt.real.max(), color='0.5', label='Reflected') pl.plot(wtime, Pdt.real/Pdt.real.max() + Prt.real/Prt.real.max(), 'k--', linewidth=4, label='Sum') pl.legend() pl.ylabel(r'Pressure $\tilde{p}(r,t)$') return Pdt+Prt, Pdt, Prt, f, wtime
def sMatrixElementCoefficients(k, n1, n2, m): A = -n1 * hankel2(m, n2 * k) * jvp(m, n1 * k) + n2 * jn(m, n1 * k) * h2vp( m, n2 * k) B = n1 * hankel1(m, n2 * k) * jvp(m, n1 * k) - n2 * jn(m, n1 * k) * h1vp( m, n2 * k) Ap = -n1 * n1 * jvp(m, n1 * k, 2) * hankel2(m, n2 * k) + n2 * n2 * jn( m, n1 * k) * h2vp(m, n2 * k, 2) Bp = n1 * n1 * jvp(m, n1 * k, 2) * hankel1(m, n2 * k) - n2 * n2 * jn( m, n1 * k) * h1vp(m, n2 * k, 2) return A, B, Ap, Bp
def exact_soln(r, theta, terms=30, r0=1, k=2 * np.pi): r = np.array(r) theta = np.array(theta) sln = np.zeros((len(r), len(theta)), dtype=np.complex128) for n in xrange(terms): eps = 2 if n else 1 sln += eps * 1j**n * np.outer( jn(n, k * r0) / hankel1(n, k * r0) * hankel1(n, k * r), np.cos(n * theta)) return -sln
def __get_extended_matrix(self, Rmn, kb, an, NX, NY): """Return the extended matrix of Method of Moments. Parameters ---------- Rmn : :class:`numpy:ndarray` Radius matrix. kb : float or :class:`numpy:ndarray` Wavenumber [1/m] an : float Radius of equivalent element radius circle. Nx, Ny : int Number of cells in each direction. Returns ------- G : :class:`numpy:ndarray` The extent matrix. """ if isinstance(kb, float) or isinstance(kb, complex): # Matrix elements for off-diagonal entries (m=/n) Gmn = 1j*np.pi*kb*an/2*spc.jv(1, kb*an)*spc.hankel1(0, kb*Rmn) # Matrix elements for diagonal entries (m==n) Gmn[NY-1, NX-1] = 1j*np.pi*kb*an/2*spc.hankel1(1, kb*an) - 1 # Extended matrix (2N-1)x(2N-1) G = np.zeros((2*NY-1, 2*NX-1), dtype=complex) G[:NY, :NX] = Gmn[NY-1:2*NY-1, NX-1:2*NX-1] G[NY:2*NY-1, NX:2*NX-1] = Gmn[:NY-1, :NX-1] G[NY:2*NY-1, :NX] = Gmn[:NY-1, NX-1:2*NX-1] G[:NY, NX:2*NX-1] = Gmn[NY-1:2*NY-1, :NX-1] else: G = np.zeros((2*NY-1, 2*NX-1, kb.size), dtype=complex) for f in range(kb.size): # Matrix elements for off-diagonal entries (m=/n) Gmn = (1j*np.pi*kb*an/2*spc.jv(1, kb[f]*an) * spc.hankel1(0, kb[f]*Rmn)) # Matrix elements for diagonal entries (m==n) Gmn[NY-1, NX-1] = (1j*np.pi*kb[f]*an/2*spc.hankel1(1, kb[f]*an) - 1) G[:NY, :NX, f] = Gmn[NY-1:2*NY-1, NX-1:2*NX-1] G[NY:2*NY-1, NX:2*NX-1, f] = Gmn[:NY-1, :NX-1] G[NY:2*NY-1, :NX, f] = Gmn[:NY-1, NX-1:2*NX-1] G[:NY, NX:2*NX-1, f] = Gmn[NY-1:2*NY-1, :NX-1] return G
def penetrable_circle(k0, k1, rad, plot_grid): # from pylab import find from scipy.special import jv, hankel1 import numpy as np x = np.vstack((plot_grid[0].ravel(), plot_grid[1].ravel())) points = x fem_xx = points[0, :] fem_xy = points[1, :] r = np.sqrt(fem_xx * fem_xx + fem_xy * fem_xy) theta = np.arctan2(fem_xy, fem_xx) npts = np.size(fem_xx, 0) a = rad n_terms = np.max([100, np.int(55 + (k0 * a)**1.01)]) Nx = plot_grid.shape[1] Ny = plot_grid.shape[2] u_inc = np.exp(1j * k0 * fem_xx) n_int = np.where(r < a) n_ext = np.where(r >= a) u_inc[n_int] = 0.0 u_plot = u_inc.reshape(Nx, Ny) u_int = np.zeros(npts, dtype=np.complex128) u_ext = np.zeros(npts, dtype=np.complex128) for n in range(-n_terms, n_terms): bessel_k0 = jv(n, k0 * rad) bessel_k1 = jv(n, k1 * rad) hankel_k0 = hankel1(n, k0 * rad) bessel_deriv_k0 = jv(n - 1, k0 * rad) - n / (k0 * rad) * jv(n, k0 * rad) bessel_deriv_k1 = jv(n - 1, k1 * rad) - n / (k1 * rad) * jv(n, k1 * rad) hankel_deriv_k0 = n / (k0 * rad) * hankel_k0 - hankel1(n + 1, k0 * rad) a_n = (1j**n) * (k1 * bessel_deriv_k1 * bessel_k0 - k0 * bessel_k1 * bessel_deriv_k0) / \ (k0 * hankel_deriv_k0 * bessel_k1 - k1 * bessel_deriv_k1 * hankel_k0) b_n = (a_n * hankel_k0 + (1j**n) * bessel_k0) / bessel_k1 u_ext += a_n * hankel1(n, k0 * r) * np.exp(1j * n * theta) u_int += b_n * jv(n, k1 * r) * np.exp(1j * n * theta) u_int[n_ext] = 0.0 u_ext[n_int] = 0.0 u_sc = u_int + u_ext u_scat = u_sc.reshape(Nx, Ny) u_tot = u_scat + u_plot return u_tot
def func(x): r = p - x R2 = np.dot(r, r) R = np.sqrt(R2) drdudrdn = -np.dot(r, vecq) * np.dot(r, vecp) / R2 dpnu = np.dot(vecp, vecq) c1 = 0.25j * k / R * hankel1(1, k * R) - 0.5 / (np.pi * R2) c2 = 0.50j * k / R * hankel1(1, k * R) - 0.25j * k2 * \ hankel1(0, k * R) - 1.0 / (np.pi * R2) c3 = -0.25 * k2 * np.log(R) / np.pi return c1 * dpnu + c2 * drdudrdn + c3
def prep_operator(self, k, Tint): A = np.eye(self._N, dtype='complex128') dv = self.x - self.x[:, None] d = np.abs(dv) np.fill_diagonal(d, 1) self.costheta = np.real(np.conj(self.normals) * dv)/d d *= k # $$ \dfrac{\partial H_n^{(1)}(z)}{\partial z} = # \dfrac{n H_n^{(1)}(z)}{z} - H_{n+1}^{(1)}(z)$$ # Kapur-Rokhlin correction # filling diagonal with 0s as per KR quad scheme D = -1j/4*fns.hankel1(1, d) @ self.costheta np.fill_diagonal(D, 0) # print("weights shape: %s"%str(self.weights.shape)) D = D * self.sp * self.weights S = 1j/4*fns.hankel1(0, d) np.fill_diagonal(S, 0) S = S * self.sp * self.weights # print(S) # implementing a 6th order correction scheme here # taken from Alex Barnett's MPSPack lib g6 = [4.967362978287758, -16.20501504859126, 25.85153761832639, -22.22599466791883, 9.930104998037539, -1.817995878141594] corrections = np.ones((self._N, self._N)) for i in range(self._N): for j in range(1, 7): corrections[i][i-j] = g6[j-1] corrections[i][(i+j) % self._N] = g6[j-1] S *= 2*corrections D *= 2*corrections A += S @ Tint.astype('complex128') - D self.S = S self.D = D self.A = A self.Text = np.linalg.inv(S) @ (D-np.eye(len(D))/2) # eigvals = np.linalg.eigvals(A) # plt.scatter(eigvals.real, eigvals.imag) # plt.xlabel("Re($\lambda$)") # plt.xlabel("Im($\lambda$)") # plt.show() return A
def computeScatteredWaveElement(kvec, p0, p1, point): """ Scattered wave contribution from a single segment @param kvec incident wave vector @param p0 starting point of the segment @param p1 end point of the segment @param point observer point @return complex value """ # xdot is anticlockwise xdot = p1 - p0 # mid point of the segment pmid = 0.5 * (p0 + p1) # segment length dsdt = numpy.sqrt(xdot.dot(xdot)) # normal vector, pointintg inwards and normalised nvec = numpy.array([ -xdot[1], xdot[0], ]) nvec /= numpy.sqrt(nvec.dot(nvec)) # from segment mid-point to observer rvec = point - pmid r = numpy.sqrt(rvec.dot(rvec)) kmod = numpy.sqrt(kvec.dot(kvec)) kr = kmod * r # Green functions and normal derivatives g = (1j / 4.) * hankel1(0, kr) dgdn = (-1j / 4.) * hankel1(1, kr) * kmod * nvec.dot(rvec) / r # contribution from the gradient of the incident wave on the surface # of the obstacle. The normal derivative of the scattered wave is # - normal derivative of the incident wave. scattered_wave = -dsdt * g * gradIncident(nvec, kvec, pmid) # shadow side: total wave is nearly zero # => scattered wave amplitude = -incident wave ampl. # # illuminated side: # => scattered wave amplitude = +incident wave ampl. shadow = 2 * ((nvec.dot(kvec) > 0.) - 0.5 ) # +1 on the shadow side, -1 on the illuminated side scattered_wave += shadow * dsdt * dgdn * incident(kvec, pmid) return scattered_wave
def dshaf11(m, z): """ This function is based on information given in "Vibration and Sound", by Philip M. Morse, 2nd Edition., pp. 316-317. """ if m == 0: y = - sqrt(0.5 * pi /z) * hankel1(1.5, z); else: y = (m / (2*m+1)) * sqrt(0.5 * pi /z) * hankel1(m - 0.5, z) t = ((m+1) / (2*m+1)) * sqrt(0.5 * pi /z) * hankel1(m + 1.5, z) y -= t return y
def two_dim_g(k0, X, Y): r = np.sqrt(X**2 + Y**2) g = 0.25j * hankel1(0., k0 * r) max_pix = 0j dx = _get_dx(X, 0) dy = _get_dx(Y, 1) for _ in range(100): r = np.sqrt((dx * np.random.uniform(-0.5, 0.5))**2 + (dy * np.random.uniform(-0.5, +0.5))**2) max_pix += 0.25j * hankel1(0., k0 * r) max_pix = max_pix / 100. g = np.where(np.isnan(g) | np.isinf(g), max_pix, g) return g
def test_cylindrical_hankel_1(): order = np.random.randint(0, 6) value = np.random.rand(1).item() * 10 assert (roundComplex(complex(NumCpp.cyclic_hankel_1_Scaler(order, value)), NUM_DECIMALS_ROUND) == roundComplex(sp.hankel1(order, value), NUM_DECIMALS_ROUND)) shapeInput = np.random.randint(20, 100, [2, ]) shape = NumCpp.Shape(shapeInput[0].item(), shapeInput[1].item()) order = np.random.randint(0, 6) value = NumCpp.NdArray(shape) valuePy = np.random.rand(shape.rows, shape.cols) * 10 value.setArray(valuePy) assert np.array_equal(roundComplexArray(NumCpp.cyclic_hankel_1_Array(order, value), NUM_DECIMALS_ROUND), roundComplexArray(sp.hankel1(order, valuePy), NUM_DECIMALS_ROUND))
def test_hankel_01_complex(ctx_factory, ref_src): ctx = ctx_factory() queue = cl.CommandQueue(ctx) if not has_double_support(ctx.devices[0]): from pytest import skip skip("no double precision support--cannot test complex bessel function") n = 10**6 np.random.seed(11) z = ( np.logspace(-5, 2, n) * np.exp(1j * 2 * np.pi * np.random.rand(n))) def get_err(check, ref): return np.max(np.abs(check-ref)) / np.max(np.abs(ref)) if ref_src == "pyfmmlib": pyfmmlib = pytest.importorskip("pyfmmlib") h0_ref, h1_ref = pyfmmlib.hank103_vec(z, ifexpon=1) elif ref_src == "scipy": spec = pytest.importorskip("scipy.special") h0_ref = spec.hankel1(0, z) h1_ref = spec.hankel1(1, z) else: raise ValueError("ref_src") z_dev = cl_array.to_device(queue, z) h0_dev, h1_dev = clmath.hankel_01(z_dev) rel_err_h0 = np.abs(h0_dev.get() - h0_ref)/np.abs(h0_ref) rel_err_h1 = np.abs(h1_dev.get() - h1_ref)/np.abs(h1_ref) max_rel_err_h0 = np.max(rel_err_h0) max_rel_err_h1 = np.max(rel_err_h1) print("H0", max_rel_err_h0) print("H1", max_rel_err_h1) assert max_rel_err_h0 < 4e-13 assert max_rel_err_h1 < 2e-13 if 0: import matplotlib.pyplot as pt pt.loglog(np.abs(z), rel_err_h0) pt.loglog(np.abs(z), rel_err_h1) pt.show()
def G1(self, facous, z_ff=10): """compute G matrix used in HIE, 1st kind""" G = np.zeros((self.xaxis.size, self.xaxis.size), dtype=np.complex_) kc = 2 * pi * facous / self.c nfi = 2 * pi * facous * self.d_ae / np.real(self.c) < z_ff ffi = np.bitwise_not(nfi) nfi[np.diag_indices_from(nfi)] = False G[nfi] = -1j / 4 * hankel1(0, kc * self.d_ae[nfi]) z = kc * self.d_ae[ffi] c = self.c G_str = '-1j / 4 * sqrt(2 / (pi * z)) * exp(1j * (z - pi / 4))' G[ffi] = ne.evaluate(G_str) g_diag = hankel1(0, kc * self.DX / (2 * e)) / (4j) G[np.diag_indices_from(G)] = g_diag return G
def f0(x, v): if v == 0: return f(x) elif v == 1: return spec.jn(10, x) elif v == 2: return spec.hankel1(0, x) elif v == 3: return spec.hankel1(10, x) elif v == 4: return spec.hankel2(0, x) elif v == 5: return spec.hankel2(10, x) else: return spec.airy(x)
def test_hankel_01_complex(ctx_factory, ref_src): ctx = ctx_factory() queue = cl.CommandQueue(ctx) if not has_double_support(ctx.devices[0]): from pytest import skip skip( "no double precision support--cannot test complex bessel function") n = 10**6 np.random.seed(11) z = (np.logspace(-5, 2, n) * np.exp(1j * 2 * np.pi * np.random.rand(n))) def get_err(check, ref): return np.max(np.abs(check - ref)) / np.max(np.abs(ref)) if ref_src == "pyfmmlib": pyfmmlib = pytest.importorskip("pyfmmlib") h0_ref, h1_ref = pyfmmlib.hank103_vec(z, ifexpon=1) elif ref_src == "scipy": spec = pytest.importorskip("scipy.special") h0_ref = spec.hankel1(0, z) h1_ref = spec.hankel1(1, z) else: raise ValueError("ref_src") z_dev = cl_array.to_device(queue, z) h0_dev, h1_dev = clmath.hankel_01(z_dev) rel_err_h0 = np.abs(h0_dev.get() - h0_ref) / np.abs(h0_ref) rel_err_h1 = np.abs(h1_dev.get() - h1_ref) / np.abs(h1_ref) max_rel_err_h0 = np.max(rel_err_h0) max_rel_err_h1 = np.max(rel_err_h1) print("H0", max_rel_err_h0) print("H1", max_rel_err_h1) assert max_rel_err_h0 < 4e-13 assert max_rel_err_h1 < 2e-13 if 0: import matplotlib.pyplot as pt pt.loglog(np.abs(z), rel_err_h0) pt.loglog(np.abs(z), rel_err_h1) pt.show()
def Ez_scat_deserialized_worker(self, params): i = params[0] j = params[1] return self.I_aux[j] * special.hankel1( 0, self.k * math.sqrt((self.x_obs[i] - self.x_aux[j])**2 + (self.y_obs[i] - self.y_aux[j])**2))
def H0(s): """ Computes and returns the value of the Hankel function in s """ if s<0.01: s = 0.01 #H0(0) = -inf value = sp.hankel1(0, s) # theoretical_value = J0(s) + 1j*Y0(s) return value
def coeff_w_m(η, m, k): M = np.array( [[sp.iv(m, η * k), -sp.hankel1(m, k)], [sp.ivp(m, η * k) / η, sp.h1vp(m, k)]] ) V = np.array([[sp.jv(m, k)], [-sp.jvp(m, k)]]) S = np.linalg.solve(M, V) return (S[0, 0], S[1, 0])
def det_M1(η, m): c = η + 1 / η return lambda z: ( sp.ivp(m, η * z, 2) * sp.hankel1(m, z) + c * sp.ivp(m, η * z) * sp.h1vp(m, z) + sp.iv(m, η * z) * sp.h1vp(m, z, 2) )
def Anl_worker(self, params): return special.hankel1( 0, self.k * math.sqrt( math.pow( self.decim_indices[params[0]] - self.decim_indices[params[1]], 2) + self.h_aux2))
def effective_coated_N0(self, filling, polarization): ''' Calculate effective medium parameters using the coated cylinder model ''' R = self.radius k = self.k_host mu_h = 1.0 R2 = R / np.sqrt(filling) # bessel functions J0 = special.jv(0, k * R2) H0 = special.hankel1(0, k * R2) JD0 = special.jvp(0, k * R2) HD0 = special.h1vp(0, k * R2) aa0 = self.coeff(0, polarization) if polarization in ['H', 'TE']: numer = JD0 + HD0 * aa0 + 0j denom = (J0 + H0 * aa0) + 0j term = -2. * mu_h / (k * R2) return term * numer / denom + 0j else: aa0 = self.coeff(0, polarization) numer = JD0 + HD0 * aa0 + 0j denom = (J0 + H0 * aa0) + 0j term = -2 * self.host_eps / (k * R2) return term * numer / denom + 0j
def effective_coated_order(self, filling, polarization, order): ''' Calculate effective medium parameters using the coated cylinder model ''' R = self.radius k = self.k_host mu_h = 1.0 R2 = R / np.sqrt(filling) # bessel functions J0 = special.jv(order, k * R2) H0 = special.hankel1(order, k * R2) JD0 = special.jvp(order, k * R2) HD0 = special.h1vp(order, k * R2) m = order #aa0 = self.coeff(1,polarization) if polarization in ['H', 'TE']: aa1 = self.coeff(m, 'TE') denom = JD0 + HD0 * aa1 + 0j numer = (J0 + H0 * aa1) + 0j sum_ = m * numer / denom term = self.host_eps / (k * R2) return term * sum_ + 0j else: aa1 = self.coeff(m, 'TM') denom = JD0 + HD0 * aa1 + 0j numer = (J0 + H0 * aa1) + 0j sum_ = numer / denom / m term = self.host_mu / (k * R2) return term * sum_ + 0j
def Mcyl(self, field, order, rho, phi, component, freq_index): n = order # bessel functions if field == "inc": k = self.kR_host[freq_index] / self.radius z1 = k * rho J1 = special.jv(order, z1) JD1 = special.jvp(order, z1) m_r = -order * k * J1 * np.sin(order * phi) / z1 m_phi = -k * JD1 * np.cos(order * phi) elif field == "sc": k = self.kR_host[freq_index] / self.radius z1 = k * rho H1 = special.hankel1(order, z1) HD1 = special.h1vp(order, z1) m_r = -n * k * H1 * np.sin(order * phi) / z1 m_phi = -k * HD1 * np.cos(order * phi) #print m_r, m_phi elif field == "int": q = self.kR_cyl[freq_index] / self.radius z2 = q * rho J2 = special.jv(order, z2) JD2 = special.jvp(order, z2) m_r = -order * q * J2 * np.sin(order * phi) / z2 m_phi = -q * JD2 * np.cos(order * phi) if component in ['r', 'rho']: return m_r elif component in ['phi']: return m_phi else: return np.array([m_r, m_phi])
def G2(self, facous, z_ff=10, mask=None, is_L=False): """compute G matrix used in HIE, 2nd kind""" G = np.zeros((self.xaxis.size, self.xaxis.size), dtype=np.complex_) nfi = 2 * pi * facous * self.d_ae / np.real(self.c) < z_ff ffi = np.bitwise_not(nfi) # only compute left triangle if is_L: nfi = np.tril(nfi) ffi = np.tril(ffi) # Apply travel time mask if mask is not None: nfi = np.bitwise_and(nfi, mask) ffi = np.bitwise_and(ffi, mask) nfi[np.diag_indices_from(nfi)] = False G[nfi] = -1j * pi * facous * self.cos_ae[nfi]\ * hankel1(1, 2 * pi * facous * self.d_ae[nfi] / self.c) \ / (2 * self.c) z = 2 * pi * facous * self.d_ae[ffi] / self.c cae = self.cos_ae[ffi] c = self.c G_str = '-1j * pi * facous * cae * sqrt(2 / (pi * z))' \ + '* exp(1j * (z - 3 * pi / 4)) / (2 * c)' G[ffi] = ne.evaluate(G_str) G[np.diag_indices_from(G)] = -self.zpp_wave \ / (4 * pi * self.grad_h ** 2) return G
def G_pseudo(beta0, kc, L, rsrc, rrcr, l_max, qmax): """Compute the psuedo-periodic greens function from rsrc to rrcr""" dx = rrcr[0] - rsrc[0] dz = rrcr[1] - rsrc[1] kr = kc * np.sqrt(dx**2 + dz**2) theta = np.arctan2(-np.abs(dx), -np.abs(dz)) # compute lattice sum coefficents s_arr = [S_Kummer(beta0, kc, L, 0, qmax)] for l in range(1, l_max + 1): Seven, Sodd = S_Kummer(beta0, kc, L, l, qmax) s_arr.append(Seven) s_arr.append(Sodd) s_arr = np.array(s_arr) eps = np.full(s_arr.size, 2) eps[0] = 1 orders = np.arange(l_max * 2 + 1) jterms = jv(orders, kr) costerms = np.cos(orders * (pi / 2 - theta)) g = hankel1(0, kr) + (eps * s_arr * jterms * costerms).sum() g *= -1j / 4 return g
def get_dirichlet_bc(self, n): '''TODO: docstring''' return -( sp.jv(n, self.get_wavenumber() * self.get_cylinder_radius()) / sp.hankel1(n, self.get_wavenumber() * self.get_cylinder_radius()))
def evaluate_T(mesh,k): px = mesh.sourceVals[0].reshape(-1,1) py = mesh.sourceVals[1].reshape(-1,1) qx = mesh.sampVals[0].reshape(1,-1) qy = mesh.sampVals[1].reshape(1,-1) r = np.sqrt( (qx-px)**2 + (qy-py)**2 ) drdn = ( (qx-px)*mesh.sampNormals[0] + (qy-py)*mesh.sampNormals[1] ) / r return 0.25j * k * drdn * hankel1(1,k*r)
def get_potentials(xy,mesh,k,incAmp,incDir): incident = incAmp * np.exp( 1j*k*np.dot(xy.T,incDir) ) x=xy[0].reshape(-1,1) y=xy[1].reshape(-1,1) sourcex=mesh.sourceVals[0].reshape(1,-1) sourcey=mesh.sourceVals[1].reshape(1,-1) r = np.sqrt( (x-sourcex)**2 + (y-sourcey)**2 ) scattered = np.sum(0.25j * mesh.amplitudes * hankel1(0,k*r),axis=1) return scattered + incident.reshape(-1,)
def Alternative_MFS(mesh,plotx,ploty,k,incDir,incAmp=1.0,tau=10,frac_samp=2,offset=0.15): mesh.MFS=True for d in mesh.dList: d.numSource = int(np.ceil(tau*k*d.length()/(2*np.pi))) d.numSamp = int(frac_samp*d.numSource) source = np.linspace(0,d.length(),d.numSource,endpoint=False) samp = np.linspace(0,d.length(),d.numSamp,endpoint=False) low=high=0 for e in d.eList: high+=e.length() xi = np.where((low<=source)==(source<high)) xi = e.limits[0] + (e.limits[1]-e.limits[0])*(source[xi]-low)/e.length() e.sourceNormals = e.normals(xi) e.sourceVals = e.vals(xi) + offset*e.sourceNormals xi = np.where((low<=samp) == (samp<high)) xi = e.limits[0] + (e.limits[1]-e.limits[0])*(samp[xi]-low)/e.length() e.sampVals = e.vals(xi) e.sampNormals = e.normals(xi) low+=e.length() d.sourceVals = np.hstack([e.sourceVals for e in d.eList]) d.sourceNormals = np.hstack([e.sourceNormals for e in d.eList]) d.sampVals = np.hstack([e.sampVals for e in d.eList]) d.sampNormals = np.hstack([e.sampNormals for e in d.eList]) mesh.sourceVals = np.hstack([d.sourceVals for d in mesh.dList]) mesh.sourceNormals = np.hstack([d.sourceNormals for d in mesh.dList]) mesh.sampVals = np.hstack([d.sampVals for d in mesh.dList]) mesh.sampNormals = np.hstack([d.sampNormals for d in mesh.dList]) # A qx = mesh.sourceVals[0].reshape(1,-1) qy = mesh.sourceVals[1].reshape(1,-1) px = mesh.sampVals[0].reshape(-1,1) py = mesh.sampVals[1].reshape(-1,1) npx = mesh.sampNormals[0].reshape(-1,1) npy = mesh.sampNormals[1].reshape(-1,1) r = np.sqrt( (qx-px)**2 + (qy-py)**2 ) drdn = ( (qx-px)*npx + (qy-py)*npy ) / r A = 0.25j * k * drdn * hankel1(1,k*r) # b vector phi = incAmp * np.exp(1j*k*np.dot(mesh.sampVals.T,incDir)) b = -(1j*k*np.dot(mesh.sampNormals.T,incDir)*phi).reshape(-1,1) mesh.amplitudes,residuals,rank,s = np.linalg.lstsq(A,b,rcond=1e-10) mesh.amplitudes = mesh.amplitudes.reshape(-1,) return get_potentials(np.vstack([plotx,ploty]),mesh,k,incAmp,incDir)
def Bescoef(k,r,a,n): """ The calculates the Bessel and Hankel function coef for the incident and scattered wave solution. spec.jv(v,z) - Bessel Func of the first kind of order v spec.jvp(v,z) - first derivative of BF of the first kinda of order v spec.h1vp(v,z) - first derivative of Hankel Func of order v spec.hankel1(v,z) - Hankel func of the first kind of order v """ kr , ka = k*r , k*a coef = -(spec.jvp(n,ka,n=1)/spec.h1vp(n,ka,n=1))*spec.hankel1(n,kr) return coef
def linton_evans_coeffs(k,incAng,numCylinders,centres,radii,M): # Four-cylinder problem #if k<=20: # M=40 #elif 20<k<=40: # M=80 #elif 40<k<=60: # M=120 #elif 60<k<=120: # M=180 #elif k>120: # M=300 N = numCylinders origin = centres a = radii i = np.arange(0,N).reshape(-1,1) j = np.arange(0,N).reshape(1,-1) R = np.sqrt((origin[j,0]-origin[i,0])**2+(origin[j,1]-origin[i,1])**2) alpha = np.angle((origin[j,0]-origin[i,0]) +1j*(origin[j,1]-origin[i,1])) q = np.repeat(np.arange(N),2*M+1).reshape(-1,1) # rows p = np.repeat(np.arange(N),2*M+1).reshape(1,-1) # cols m = np.repeat([np.arange(-M,M+1)],N,axis=0).reshape(-1,1) # rows n = np.repeat([np.arange(-M,M+1)],N,axis=0).reshape(1,-1) # cols # Right-hand vector Iq = np.exp(1j*k*(origin[q,0]*np.cos(incAng)+origin[q,1]*np.sin(incAng))) exponential1 = np.exp(1j*m*(np.pi/2-incAng)) RHS = - Iq * exponential1 # Left-hand side matrix Znp = jvp(n,k*a[p]) / h1vp(n,k*a[p]) exponential2 = np.exp(1j*(n-m)*alpha[p,q]) Hnm = hankel1(n-m,k*R[p,q]) LHS = Znp * exponential2 * Hnm Identity = np.identity(2*M+1) for cyl in range(N): LHS[cyl*(2*M+1):(cyl+1)*(2*M+1),cyl*(2*M+1):(cyl+1)*(2*M+1)] = Identity # Solve for values of Anq A=np.linalg.solve(LHS,RHS) return A
def hankel1(n, z): """Bessel function of third kind (Hankel function) of order n at kr. Wraps scipy.special.hankel1(n, z) Parameters ---------- n : array_like Order z: array_like Argument Returns ------- H1 : array_like Values of Hankel function of order n at position z """ return scy.hankel1(n, z)
def ddn_helmholtz_fs(k, D_a, x): """ (float, Antenna, numpy.array) -> numpy.array We assume that x is a single 2-vector not on the Antenna D_a. Returns a D_a.n_points() by 1 array (shape = (D_a.n_points(), ))representing the values dPhi/dn(y,x) for each value y on the antenna array D_a. """ assert x.size==2 and k > 0 x = np.reshape(x,2) #makes sure that x has shape (2,) #need to compute normal vectors to each boundary of antenna array y = D_a.get_boundary() #y.shape = (2, D_a.n_points()) nu = D_a.nu() #shape = (2, D_a.n_points()) ynu = np.sum(y*nu, 0) #Ynu.shape = (D_a.n_points(),) xnu = np.dot(nu.T, x) #xnu.shape = (D_a.n_points(),) nu_diff_mat = ynu - xnu #nu_diff_mat.shape = (D_a.n_points(),) dist_array = np.linalg.norm(y-np.reshape(x,(2,1)), axis=0) #dist_array.shape = (D_a.n_points(),) return -(1j*k/4)*nu_diff_mat/dist_array*hankel1(1,k*dist_array)
def helmholtz_fs(k, x, y): """ (float, numpy.array, numpy.array) -> numpy.array Compute the value of the fundamental solution to the Helmholtz equation with wave number k. x is a 2 by D_c.n_points() array of points along a particular ControlRegion object. y is a 2 by D_a.n_points() array of points along the boundary of an Antenna object. Output is an D_a.n_points() by D_c.n_points() array of values. The columns correspond to a fixed point in the control region (x) while varying the point on the antenna array (y) """ assert x.shape[0]==2 and y.shape[0]==2 and k > 0 nc = x.shape[1] na = y.shape[1] result = np.zeros((nc,na), dtype=complex) for i in range(nc): result[i,:] = 1j/4*hankel1(0,k*np.linalg.norm(np.reshape(x[:,i],(2,1))-y, axis=0)) return result.T #shape is (na, nc)
def computeScatteringMatrix(self,Mmax): # -- Prepare scattering matrix. scatMat = np.zeros((2*Mmax+1,2*Mmax+1), dtype=np.complex) for n in range(2*Mmax+1): m = n-Mmax # -- Prepare the vector and matrix b = np.zeros((self.nTriangles), dtype=np.complex) M = np.zeros((self.nTriangles,self.nTriangles), dtype=np.complex) for i in range(self.nTriangles): b[i] = jn(m, self.k*np.linalg.norm(self.centerPoints[i]))*np.exp(1j*m*user_mod(np.arctan2(self.centerPoints[i,1],self.centerPoints[i,0]),2*np.pi)) for j in range(self.nTriangles): if (i!=j): d = self.k*np.linalg.norm(self.centerPoints[i]-self.centerPoints[j]) phi1 = user_mod(np.arctan2(self.centerPoints[i,1],self.centerPoints[i,0]),2*np.pi) phi2 = user_mod(np.arctan2(self.centerPoints[j,1],self.centerPoints[j,0]),2*np.pi) M[i,j] = self.potential*self.k*self.k*1j*hankel1(0, d)*self.areas[j]/4.0 x = np.linalg.solve(np.eye(self.nTriangles,self.nTriangles, dtype=np.complex)-M,b) fig2 = plt.figure(figsize=(3,3)) ax2 = fig2.add_subplot(111) ax2.axis('off') plt.tripcolor(self.points[:,0], self.points[:,1],self.triangulation.simplices, np.abs(x)) plt.savefig("intensityTest-%s.pdf" %(self.N)) # -- We compute the corresponding line of the scattering matrix. for k in range(2*Mmax+1): mp = k-Mmax Smm = 0.0 for h in range(self.nTriangles): d = self.k*np.linalg.norm(self.centerPoints[h]) phi = user_mod(np.arctan2(self.centerPoints[h,1],self.centerPoints[h,0]),2*np.pi) Smm += self.potential*jn(mp,d)*np.exp(-1j*mp*phi)*x[h]*self.areas[h] Smm = self.k*self.k*1j*Smm/2.0 Smm += (1.0 if mp==m else 0.0) scatMat[k,n] = Smm return scatMat
def ddn_helmholtz_fs_j(k, D_a, x, j): """ (number, PolarArray, numpy.array, int) -> numpy.array This is a more compartmentalized version of ddn_helmholtz_fs (works only for PolarAntennaArray). Here we just want to output the values of the normal derivative for y on the boundary of the jth antenna where j ranges from 0 to a.n_antennas-1. Again we expect that x is a 2-vector (i.e. x.size = 2). k is also positive. """ assert isinstance(D_a, (antenna.PolarArray, antenna.Polar)) assert x.size==2 and k > 0 x = np.reshape(x,2) #makes sure that x has shape (2,) nu = D_a.nu_j() y = D_a.get_boundary_j(j) ynu = np.sum(y*nu, 0) #Ynu.shape = (n,) xnu = np.dot(nu.T, x) #xnu.shape = (n,) nu_diff_mat = ynu - xnu #nu_diff_mat.shape = (n,) dist_array = np.linalg.norm(y-np.reshape(x,(2,1)), axis=0) #dist_array.shape = (n,) return -(1j*k/4)*nu_diff_mat/dist_array*hankel1(1,k*dist_array)
def cylinder(wavenumber,xPlotPoints,yPlotPoints,radius=1.0): """ Analytical potential on hard cylinder with [1,0] incident wave (Jones)""" x = xPlotPoints y = yPlotPoints theta = np.arctan2(y,x) numPoints = len(x) nans=False,False N = 100 while any(nans)==False: N += 50 n = np.arange(0,N) neumann = 2*np.ones(N); neumann[0]=1 dJ = jvp(n,wavenumber*radius,1) H1 = hankel1(n,wavenumber*radius) dH1 = h1vp(n,wavenumber*radius,1) nans = np.isnan(dJ) + np.isnan(H1) + np.isnan(dH1) dJ = dJ.compress(np.logical_not(nans)) H1 = H1.compress(np.logical_not(nans)) dH1 = dH1.compress(np.logical_not(nans)) neumann = neumann.compress(np.logical_not(nans)) n = n.compress(np.logical_not(nans)) total = (-neumann * (1j**n) * dJ * H1 / dH1).reshape(-1,1) cosines = np.cos(n.reshape(-1,1)*theta) total = total * cosines incPotential = np.exp(1j*wavenumber*x).reshape(numPoints) fullPotential = np.sum(total,axis=0) + incPotential return fullPotential
def Bn(k,r0,n): b=complex(spe.jv(n, k*r0)) a=complex(spe.hankel1(n, k*r0)) A=1j**n return -A*b/a
def Field_scat(k,r0,r,alpha,theta,N): F=Bn(k,r0,0)*spe.hankel1(0, k*r) for n in range(1,N+1): F+=Bn(k,r0,n)*spe.hankel1(n, k*r)*2*np.cos(n*(theta-alpha)) return F
def hankel1d(n, z): """Derivative of hankel1 (from Wolfram MathWorld)""" return (n * hankel1(n, z) / z) - hankel1(n+1, z)
def sMatrixElementCoefficients(k,n1,n2,m): A = -n1*hankel2(m,n2*k)*jvp(m,n1*k)+n2*jn(m,n1*k)*h2vp(m,n2*k) B = n1*hankel1(m,n2*k)*jvp(m,n1*k)-n2*jn(m,n1*k)*h1vp(m,n2*k) Ap = -n1*n1*jvp(m,n1*k,2)*hankel2(m,n2*k)+n2*n2*jn(m,n1*k)*h2vp(m,n2*k,2) Bp = n1*n1*jvp(m,n1*k,2)*hankel1(m,n2*k)-n2*n2*jn(m,n1*k)*h1vp(m,n2*k,2) return A, B, Ap, Bp
def __call__(self,x,y,nx=None,ny=None): return 1j/4*hankel1(0,self.k*absdiff(x,y))
def hankel1_ratio(m, x): "Calculates the ratio of Hankel functions: hankel_ratio = hankel1'(m,x)/hankel1(m,x)" br = x * hankel1(m - 1, x) / hankel1(m, x) - m if any(isnan(br)) or any(isinf(br)): logging.error("Nan in Scipy Bessel: compile bessel module") return br
def Assemble_Helmholtz_CBIE_Element(self, e, quadrature): px, py = self.mesh.collocation_points px = px.reshape(-1, 1) py = py.reshape(-1, 1) # Change of integration interval to element local coordinate limits xi = (quadrature.xi * 0.5 * (e.limits[1] - e.limits[0]) + 0.5 * (e.limits[0] + e.limits[1])).reshape(-1) Jacobian = quadrature.w * 0.5 * (e.limits[1] - e.limits[0]) # Create integration subdivisions for large elements ( > lambda/4 ) length = e.length() if length > (2 * np.pi / self.k) / 4: S = int(np.ceil(2.0 * self.k * length / np.pi)) s = np.arange(0, S).reshape(-1, 1) xi = ((xi - e.limits[0] + (e.limits[1] - e.limits[0]) * s) / S + e.limits[0]).reshape(-1) Jacobian = np.repeat([Jacobian], S, axis=0).reshape(1, -1) Jacobian /= 1.0 * S # It is possible to use e.vals, e.normals and e.J to find the integration # coordinates, their normals and Jacobians. # However, it is more efficient to evaluate the shape functions here # and use them to find qx,qy,nq,Jxi as the same shape functions are # multiplied by the planewave enrichment in a few lines ... # # However, this does not work for my PU-BEM simulations as these values # are hard-coded into the elements are nothing to do with the shape # functions. # # Hence, we check for an 'ExactElement' element to determine # the best method try: e.ExactElement except: e.ExactElement = False if e.ExactElement: qx, qy = e.vals(xi) nq = e.normals(xi) Jxi = e.J(xi) ShapeFunctions = e.shape_functions(xi) else: # Shape functions and derivatives at xi coordinates ShapeFunctions = e.shape_functions(xi, 1) # Integration coordinates qx, qy = np.dot(e.P, ShapeFunctions[:, :, 0].T) Jxi = np.dot(e.P, ShapeFunctions[:, :, 1].T) nq = np.vstack([Jxi[1, :], -Jxi[0, :]]) / np.sqrt(np.sum(Jxi ** 2, axis=0)) Jxi = np.sqrt(np.sum(Jxi ** 2, axis=0)) Jacobian *= Jxi r = np.sqrt((qx - px) ** 2 + (qy - py) ** 2) drdnq = ((qx - px) * nq[0] + (qy - py) * nq[1]) / r # Evaluate kernel Kernel = -1j * self.k / 4 * hankel1(1, r * self.k) * drdnq InterpolationBasis = np.repeat(ShapeFunctions[:, :, 0], e.shapeFunList[0].M, axis=1) # Assumes global M !!!! InterpolationBasis = np.asarray(InterpolationBasis, np.complex) # Make InterpolationBasis a complex matrix InterpolationBasis *= np.vstack([dof(qx, qy) for s in e.shapeFunList for dof in s.DegreesOfFreedomList]).T return np.dot(Kernel, Jacobian.reshape(-1, 1) * InterpolationBasis)
if __name__ == '__main__': mesh = [25, 50, 100, 200, 300,500,1000,2000] convergence = np.zeros((0,2)) for nPoints in mesh: y = homoCircle(nPoints, 1.0, 2.0, 1.0, 1.0, 1) scatMat = y.computeScatteringMatrix(y.Mmax) analScatMat = np.zeros(2*y.Mmax+1, dtype=complex) zc = y.nc*y.k zo = y.no*y.k eta = y.nc/y.no for i in range(2*y.Mmax+1): m = i-y.Mmax num = -(eta*jvp(m,zc)*hankel2(m,zo)-jn(m,zc)*h2vp(m,zo)) den = eta*jvp(m,zc)*hankel1(m,zo)-jn(m,zc)*h1vp(m,zo) analScatMat[i] = num/den err = np.amax(np.abs(np.diag(analScatMat)-scatMat)) print(err) print(analScatMat) # -- Mean areas of triangles convergence = np.insert(convergence, len(convergence), [np.mean(y.areas), err],axis=0) fig1 = plt.figure(figsize=(5,3)) ax1 = fig1.add_subplot(111) plt.plot(convergence[:,0],convergence[:,1], ls='--', marker='o', label=r"Numerical Error") p = np.polyfit(np.log(convergence[:,0]),np.log(convergence[:,1]),1) ynew = np.exp(np.polyval(p,np.log(convergence[:,0]))) plt.plot(convergence[:,0],ynew, label=r"Power-law fit: $\alpha=%0.2g$" %(p[0]))
def trace(self, D_c, k): """ (controlregion.ControlRegion) -> numpy.array """ x = D_c.get_boundary() return (1j/4)*hankel1(0,k*np.linalg.norm(x - np.reshape(self.x0, (2,1)), axis=0))
def hankel1p(m, z): return hankel1(m - 1, z) - hankel1(m, z) * m / z
def hankel(j, nu, z): if j==1: return hankel1(nu, z) elif j==2: return hankel2(nu, z) raise ValueError("j must be either 1 or 2")
def Green2D(self, r): 'Model the 2D Green\'s function' # Correct: -0.5j * hankel2(0, self.k*r) return self.scaleterm * self.rho * (-0.5j * hankel1(0, self.k*r))
def Green2D(self, r): # Correct: -0.5j * hankel2(0, self.k*r) return self.scaleterm * (-0.5j * hankel1(0, self.k*r))
def rfn(self, n, x): return ss.hankel1(n,x)
def __call__(self,x,y,nx=None,ny=None): w=x-y a=sqrt(w[0]**2+w[1]**2) return -self.k*1j/4*hankel1(1,self.k*a)*(nx[0]*w[0]+nx[1]*w[1])/a
def findBestAng(freq,dx): '''for a particular frequency, find the best PML complex angle Universal for both te, tm models, but calculates based on the TE model ''' import te print 'blast -- recalculating proper PML for f = ' + repr(freq) # set some internal parameters nx = 99 ny = nx dy = dx # this means free space eHS = 1.0 sHS = 0 # need basic constants epso = 8.854e-12 muo = 4.0*np.pi*1e-7 c = 1/np.sqrt(muo*epso) # to calculate the Greens function, the true spatial locations are needed x = np.array(range(nx))*dx - dx*(nx/2) Y,X = np.meshgrid(x, x); dist = np.sqrt(Y**2+X**2) k = (2*np.pi)/(c/freq) bbx = dx*dx*(1j/4)*spec.hankel1(0,k*dist) mdpt = nx/2 # the center contains a singularity, but we'll be forgiving and finite bbx[mdpt,mdpt] = 0.25*bbx[mdpt+1,mdpt] + 0.25*bbx[mdpt-1,mdpt] + 0.25*bbx[mdpt,mdpt+1] + 0.25*bbx[mdpt,mdpt-1] # create a mask so that PML effects don't adversely affect the quality of the solutions mask = np.ones(bbx.shape) mask[:15,:] =0 mask[(nx-15):(nx),:] = 0 mask[:,:15]=0 mask[:,(nx-15):(nx)] = 0 lo = 0 hi = 5 # do two loops over different ranges to get a more precise estimate for tune in range(2): localError = np.zeros(50) angChoice = np.logspace(lo,hi,50) for i in range(50): # Create a single new object on frequency # use the te routine for this bce = te.solver(freq,0.0,'TE') bce.setspace(nx,ny,dx,dy) bce.setmats(eHS, sHS, nx/2) bce.makeFD(angChoice[i]) bce.makeGradOper() bce.pointSource(49, 49) bce.fwd_solve(0) u = bce.parseFields(bce.sol[0]) localError[i] = np.linalg.norm((u[0] - bbx)*mask,'fro') # print 'ang = ' + repr(angChoice[i]) + ' local error ' + repr(localError[i]) minIdx = np.argmin(localError) lo = np.log10(angChoice[max(0,minIdx-1)]) hi = np.log10(angChoice[min(50,minIdx+1)]) # print lo # print hi # bce = fwd(freq) # bce.setspace(nx,ny,dx,dy) # bce.setmats(eHS, sHS, nx/2) # # # pmc = 22.229964825261945 # # angChoice[minIdx] # bce.makeFD(31.2759) # bce.point_source(nx/2, ny/2) # bce.fwd_solve(0) # M = bce.nabla2 # matOut.matlab.savemat('bstN', {'M':M}) #do some representative plots # plt.figure(1) # plt.plot(angChoice, localError) # # do some plotting # plt.figure(13) # plt.subplot(221) # plt.imshow((bce.sol[0].real*mask)) # plt.colorbar() # # plt.subplot(222) # plt.imshow((bbx.real*mask)) # plt.colorbar() # # plt.subplot(223) # plt.imshow((bce.sol[0].imag*mask)) # plt.colorbar() # # plt.subplot(224) # plt.imshow((bbx.imag*mask)) # plt.colorbar() # # lkl = bce.sol[0] # plt.figure(44) # plt.plot(np.arange(nx), lkl[49,:].real, np.arange(nx), bbx[49,:].real) # # plt.figure(4) # plt.subplot(121) # plt.imshow((bce.sol[0]-bbx).real) # plt.colorbar() # plt.show() return angChoice[minIdx]
def ratioHankelFunctions(m1, m2, z): return hankel2(m2,z)/hankel1(m1,z)