def test_spherical_index(): """test the conversion of the spherical index""" # check initial state assert spherical.spherical_index_lm(0) == (0, 0) assert spherical.spherical_index_k(0, 0) == 0 # check conversion for k in range(20): l, m = spherical.spherical_index_lm(k) assert spherical.spherical_index_k(l, m) == k # check order k = 0 for l in range(4): for m in range(-l, l + 1): assert spherical.spherical_index_k(l, m) == k k += 1 for l in range(4): k_max = spherical.spherical_index_k(l, l) assert spherical.spherical_index_count(l) == k_max + 1 for l in range(4): for m in range(-l, l + 1): is_optimal = m == l k = spherical.spherical_index_k(l, m) assert spherical.spherical_index_count_optimal(k + 1) == is_optimal
def __init__( self, position: np.ndarray, radius: float, interface_width: float = None, amplitudes: np.ndarray = None, ): r""" Args: position (:class:`~numpy.ndarray`): Position of the droplet center radius (float): Radius of the droplet interface_width (float, optional): Width of the interface amplitudes (:class:`~numpy.ndarray`): Perturbation amplitudes :math:`\epsilon_{l,m}`. Note that the zero-th mode, which would only change the radius, is skipped. Consequently, the length of the array needs to be 0, 3, 8, 15, 24, ... to capture perturbations of the highest mode consistently. """ super().__init__(position, radius, interface_width, amplitudes) num_modes = len(self.amplitudes) + 1 if not spherical.spherical_index_count_optimal(num_modes): logger = logging.getLogger(self.__class__.__name__) l, _ = spherical.spherical_index_lm(num_modes) opt_modes = spherical.spherical_index_count(l) - 1 logger.warning( "The length of `amplitudes` should be such that all orders are " f"captured for the perturbations with the highest degree ({l}). " f"Consider increasing the size of the array to {opt_modes}.")
def interface_curvature(self, θ, φ): r"""calculates the mean curvature of the interface of the droplet For simplicity, the effect of the perturbations are only included to linear order in the perturbation amplitudes :math:`\epsilon_{l,m}`. Args: θ (float or array): Azimuthal angle (in :math:`[0, \pi]`) φ (float or array): Polar angle (in :math:`[0, 2\pi]`) Returns: An array with the curvature at the interfacial points associated with the angles """ Yk = spherical.spherical_harmonic_real_k correction = 0 for k, a in enumerate(self.amplitudes, 1): # skip zero-th mode! if a != 0: l, _ = spherical.spherical_index_lm(k) hk = (l**2 + l - 2) / 2 correction = a * hk * Yk(k, θ, φ) return 1 / self.radius + correction / self.radius**2