Beispiel #1
0
 def test_besselk0e(self):
     xs = [0.1, 1.0, 10.0]
     for x in xs:
         sp = k0e(x)
         hal = besselk0e(x)
         relerr = abs((sp - hal) / sp)
         self.assertLessEqual(relerr, 0.05)
Beispiel #2
0
    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 k0e(x):
    if np.iscomplexobj(x):
        return special.kve(0,x)
    else:
        return special.k0e(x)
Beispiel #6
0
    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