def test_besselk1e(self): xs = [0.1, 1.0, 10.0] for x in xs: sp = k1e(x) hal = besselk1e(x) relerr = abs((sp - hal) / sp) self.assertLessEqual(relerr, 0.05)
def logK1e_2ndderiv(x): """Slow and probably inaccurate for large x. For testing only.""" f = special.k1e(x) k1 = special.kvp(1,x,1) k2 = special.kvp(1,x,2) e = np.exp(x) f1 = f + e*k1 f2 = f1 + e*(k1+k2) return (f2*f - f1**2) / f**2
def g(theta, x): sqr0 = sqrt(delta ** 2 + (x - mu) ** 2) sqr1 = sqrt(delta ** 2 + (x - theta - mu) ** 2) a = sqrt(alpha * delta / pi) * special.k1e(alpha * sqr0) * sqrt(sqr1) / (sqr0 * sqrt(special.k1e(alpha * sqr1))) * exp(0.5 * (delta * sqrt(alpha ** 2 - beta ** 2) + beta * (x + theta - mu)) - alpha * sqr0 + 0.5 * alpha * sqr1) if a == 0: return 0 else: b = (50 * (exp(x+log(a)) - K*a)) ** 2 return b
def setBC(self, ky=None): if self.bc_type == "Dirichlet": return if getattr(self, "_MBC", None) is None: self._MBC = {} if ky in self._MBC: # I have already created the BC matrix for this wavenumber return if self.bc_type == "Neumann": alpha, beta, gamma = 0, 1, 0 else: mesh = self.mesh boundary_faces = mesh.boundary_faces boundary_normals = mesh.boundary_face_outward_normals n_bf = len(boundary_faces) # Top gets 0 Neumann alpha = np.zeros(n_bf) beta = np.ones(n_bf) gamma = 0 # assume a source point at the middle of the top of the mesh middle = np.median(mesh.nodes, axis=0) top_v = np.max(mesh.nodes[:, -1]) source_point = np.r_[middle[:-1], top_v] r_vec = boundary_faces - source_point r = np.linalg.norm(r_vec, axis=-1) r_hat = r_vec / r[:, None] r_dot_n = np.einsum("ij,ij->i", r_hat, boundary_normals) # determine faces that are on the sides and bottom of the mesh... if mesh._meshType.lower() == "tree": not_top = boundary_faces[:, -1] != top_v else: # mesh faces are ordered, faces_x, faces_y, faces_z so... is_b = make_boundary_bool(mesh.shape_faces_y) is_t = np.zeros(mesh.shape_faces_y, dtype=bool, order="F") is_t[:, -1] = True is_t = is_t.reshape(-1, order="F")[is_b] not_top = np.zeros(boundary_faces.shape[0], dtype=bool) not_top[-len(is_t):] = ~is_t # use the exponentialy scaled modified bessel function of second kind, # (the division will cancel out the scaling) # This is more stable for large values of ky * r # actual ratio is k1/k0... alpha[not_top] = (ky * k1e(ky * r) / k0e(ky * r) * r_dot_n)[not_top] B, bc = self.mesh.cell_gradient_weak_form_robin(alpha, beta, gamma) # bc should always be 0 because gamma was always 0 above self._MBC[ky] = B
def test_besselk_larger(self, dtype): x = np.random.uniform(1., 30., size=int(1e4)).astype(dtype) try: from scipy import special # pylint: disable=g-import-not-at-top self.assertAllClose( special.k0(x), self.evaluate(special_math_ops.bessel_k0(x))) self.assertAllClose( special.k0e(x), self.evaluate(special_math_ops.bessel_k0e(x))) self.assertAllClose( special.k1(x), self.evaluate(special_math_ops.bessel_k1(x))) self.assertAllClose( special.k1e(x), self.evaluate(special_math_ops.bessel_k1e(x))) except ImportError as e: tf_logging.warn('Cannot test special functions: %s' % str(e))
def k012e(x): """Returns k0e(x), k1e(x) and k2e(x) for real or complex x. For real x, the fast exponentially scaled K_n Bessel functions, k0e end k1e are defined in scipy.special, but not ke2, which is computed here from the other two using the recurion: K_n(x) = K_{n-2}(x) + 2(n-1)/z * K_{n-1}(x) For complex x, kve(0,x) and kve(1,x) and the recursion are used. Returns the outputs all three functions, evaluated at x. """ if np.iscomplexobj(x): k0 = special.kve(0,x) k1 = special.kve(1,x) k2 = k0 + 2.0*k1/x else: k0 = special.k0e(x) k1 = special.k1e(x) k2 = k0 + 2.0*k1/x return k0, k1, k2 #def ddxlogK1e(z): """
def _pdf(self, x, a, b): gamma = sqrt(a**2 - b**2) fac1 = a / pi * exp(gamma) sq = sqrt(1 + x**2) return (fac1 * special.k1e(a * sq) * exp(b*x - a*sq) / sq)
def k1e(x): if np.iscomplexobj(x): return special.kve(1,x) else: return special.k1e(x)
def besselkve(self, v, x): if v == 1: return special.k1e(x) else: return special.kve(v, x)
def setBC(self, ky=None): if self.bc_type == "Dirichlet": # do nothing raise ValueError( "Dirichlet conditions are not supported in the Nodal formulation" ) elif self.bc_type == "Neumann": if self.verbose: print( "Homogeneous Neumann is the natural BC for this Nodal discretization." ) return else: if getattr(self, "_AvgBC", None) is None: self._AvgBC = {} if ky in self._AvgBC: return mesh = self.mesh # calculate alpha, beta, gamma at the boundary faces boundary_faces = mesh.boundary_faces boundary_normals = mesh.boundary_face_outward_normals n_bf = len(boundary_faces) alpha = np.zeros(n_bf) # assume a source point at the middle of the top of the mesh middle = np.median(mesh.nodes, axis=0) top_v = np.max(mesh.nodes[:, -1]) source_point = np.r_[middle[:-1], top_v] r_vec = boundary_faces - source_point r = np.linalg.norm(r_vec, axis=-1) r_hat = r_vec / r[:, None] r_dot_n = np.einsum("ij,ij->i", r_hat, boundary_normals) # determine faces that are on the sides and bottom of the mesh... if mesh._meshType.lower() == "tree": not_top = boundary_faces[:, -1] != top_v else: # mesh faces are ordered, faces_x, faces_y, faces_z so... is_b = make_boundary_bool(mesh.shape_faces_y) is_t = np.zeros(mesh.shape_faces_y, dtype=bool, order="F") is_t[:, -1] = True is_t = is_t.reshape(-1, order="F")[is_b] not_top = np.zeros(boundary_faces.shape[0], dtype=bool) not_top[-len(is_t):] = ~is_t # use the exponentiall scaled modified bessel function of second kind, # (the division will cancel out the scaling) # This is more stable for large values of ky * r # actual ratio is k1/k0... alpha[not_top] = (ky * k1e(ky * r) / k0e(ky * r) * r_dot_n)[not_top] P_bf = self.mesh.project_face_to_boundary_face AvgN2Fb = P_bf @ self.mesh.average_node_to_face AvgCC2Fb = P_bf @ self.mesh.average_cell_to_face AvgCC2Fb = sdiag(alpha * (P_bf @ self.mesh.face_areas)) @ AvgCC2Fb self._AvgBC[ky] = AvgN2Fb.T @ AvgCC2Fb