def far_field_point_matching(source, position, radius, k, lmax, sampling=6): """Decompose a source into VSHs using the point matching method in the far field Returns p_src[2,rmax] Arguments: source source object position position around which to decompose radius radius of sphere for sampling the source field k medium wavenumber lmax maximum number of multipoles sampling angular points sampled per pi radians (default: 5) """ position = np.asarray(position) points = sample_sphere_point_matching(position, radius, sampling) Npoints = points.shape[1] X = points[0] Y = points[1] Z = points[2] _, THETA, PHI = coordinates.cart_to_sph(X, Y, Z, origin=position) rmax = vsh.lmax_to_rmax(lmax) E_src = np.zeros([2, Npoints], dtype=complex) E_vsh = np.zeros([2, Npoints, 2, rmax], dtype=complex) # fields in the upper-hemisphere are zero idx = THETA >= np.pi / 2 E_src[:, idx] = source.spherical_ingoing(THETA[idx], PHI[idx], k) # phase correction for moving away from the center of the source rhat, *_ = coordinates.sph_basis_vectors(THETA, PHI) delta = source.center - position phase = k * np.einsum('ij,i', rhat, delta) E_src *= np.exp(1j * phase) for i, n, m in vsh.mode_indices(lmax): Nfunc, Mfunc = vsh.VSH(n, m, mode=vsh.vsh_mode.ingoing) Emn_val = vsh.Emn(m, n) E_vsh[..., 0, i] = -1j * Emn_val * Nfunc(radius, THETA, PHI, k)[1:] E_vsh[..., 1, i] = -1j * Emn_val * Mfunc(radius, THETA, PHI, k)[1:] column = E_src.reshape([2 * Npoints]) matrix = E_vsh.reshape([2 * Npoints, 2 * rmax]) sol = np.linalg.lstsq(matrix, column, rcond=None) p_src = sol[0] return np.reshape(p_src, [2, rmax])
def near_field_point_matching(source, position, size, k, lmax, sampling): """Decompose a source into VSHs using the point matching method in the near field Returns p_src[2,rmax] Arguments: source source object position position around which to decompose size size of xy planar region to perform point matching over k medium wavenumber lmax maximum number of multipoles sampling number of sampling points along a dimension """ points = sample_plane_point_matching(position, size, sampling) Npoints = points.shape[1] X = points[0] Y = points[1] Z = points[2] RAD, THETA, PHI = coordinates.cart_to_sph(X, Y, Z + 1e-9, origin=position) rmax = vsh.lmax_to_rmax(lmax) E_src = source.E_field(X, Y, Z, k)[:2] H_src = source.H_field(X, Y, Z, k)[:2] # TODO: is this true? # H_src = E_src[::-1] E_vsh = np.zeros([2, Npoints, 2, rmax], dtype=complex) for i, n, m in vsh.mode_indices(lmax): Nfunc, Mfunc = vsh.VSH(n, m, mode=vsh.vsh_mode.incident) Emn_val = vsh.Emn(m, n) E_vsh[..., 0, i] = -1j * Emn_val * coordinates.vec_sph_to_cart( Nfunc(RAD, THETA, PHI, k), THETA, PHI)[:2] E_vsh[..., 1, i] = -1j * Emn_val * coordinates.vec_sph_to_cart( Mfunc(RAD, THETA, PHI, k), THETA, PHI)[:2] H_vsh = -1j * E_vsh[..., ::-1, :] column = np.concatenate([E_src.reshape([-1]), H_src.reshape([-1])]) matrix = np.concatenate( [E_vsh.reshape([-1, 2 * rmax]), H_vsh.reshape([-1, 2 * rmax])]) sol = np.linalg.lstsq(matrix, column, rcond=None) p_src = sol[0] return np.reshape(p_src, [2, rmax])
def cluster_coefficients(positions, p_scat, k, origin, lmax=None): """Solve for the cluster scattering coefficients of N particles around an origin Arguments: positions[N,3] particle positions p_scat[N,2,rmax] scattering coefficients k medium wavenumber origin position around which to calculate the cluster coefficients lmax (optional) compute scattering for up to lmax terms (default: lmax of input p/q) """ Nparticles = positions.shape[0] rmax_in = p_scat.shape[-1] lmax_in = vsh.rmax_to_lmax(rmax_in) if lmax is None: lmax = lmax_in rmax = vsh.lmax_to_rmax(lmax) p_cluster = np.zeros([2, rmax], dtype=complex) for i in range(Nparticles): if np.all(positions[i] == origin): p_cluster[0, :rmax_in] += p_scat[i, 0, :rmax_in] p_cluster[1, :rmax_in] += p_scat[i, 1, :rmax_in] continue rij = origin - positions[i] rad, theta, phi = coordinates.cart_to_sph(*rij) for r, n, m in vsh.mode_indices(lmax): for rp, v, u in vsh.mode_indices(lmax_in): a = p_scat[i, 0, rp] b = p_scat[i, 1, rp] A, B = vsh.vsh_translation(m, n, u, v, rad, theta, phi, k, vsh.vsh_mode.incident) p_cluster[0, r] += a * A + b * B p_cluster[1, r] += a * B + b * A return p_cluster