Exemplo n.º 1
0
def block_rotation_matrix_D_svwf(l_max, m_max, alpha, beta, gamma, wdsympy=False):
    """Rotation matrix for the rotation of SVWFs between the labratory 
    coordinate system (L) and a rotated coordinate system (R)
    
    Args:
        l_max (int):      Maximal multipole degree
        m_max (int):      Maximal multipole order
        alpha (float):    First Euler angle, rotation around z-axis, in rad
        beta (float):     Second Euler angle, rotation around y'-axis in rad
        gamma (float):    Third Euler angle, rotation around z''-axis in rad
        wdsympy (bool):   If True, Wigner-d-functions come from the sympy toolbox
        
    Returns:
        rotation matrix of dimension [blocksize, blocksize]
    """
    
    b_size = flds.blocksize(l_max, m_max)
    rotation_matrix = np.zeros([b_size, b_size], dtype=complex)
    
    for l in range(l_max + 1):
        mstop = min(l, m_max)
        for m1 in range(-mstop, mstop + 1):
            for m2 in range(-mstop, mstop + 1):
                rotation_matrix_coefficient = mathfunc.wigner_D(l, m1, m2, alpha, beta, gamma, wdsympy)
                for tau in range(2):
                    n1 = flds.multi_to_single_index(tau, l, m1, l_max, m_max)
                    n2 = flds.multi_to_single_index(tau, l, m2, l_max, m_max)
                    rotation_matrix[n1, n2] = rotation_matrix_coefficient

    return rotation_matrix
Exemplo n.º 2
0
 def relative_difference_Tmatrices(Tmat_s, lmax_s, mmax_s, Tmat_l,
                                   lmax_l, mmax_l):
     n_list_s = np.zeros(len(Tmat_s), dtype=int)
     n_list_l = np.zeros(len(Tmat_s), dtype=int)
     idx = 0
     for tau in range(2):
         for l in range(1, lmax_s + 1):
             for m in range(np.max([-l, -mmax_s]),
                            np.min([l, mmax_s]) + 1):
                 n_list_s[idx] = flds.multi_to_single_index(
                     tau, l, m, lmax_s, mmax_s)
                 n_list_l[idx] = flds.multi_to_single_index(
                     tau, l, m, lmax_l, mmax_l)
                 idx += 1
     row, column = np.meshgrid(n_list_s, n_list_s)
     row2, column2 = np.meshgrid(n_list_l, n_list_l)
     TMat_temp = np.zeros([len(Tmat_l), len(Tmat_l)], dtype=complex)
     TMat_temp[row2, column2] = Tmat_s[row, column]
     return np.linalg.norm(Tmat_l - TMat_temp) / np.linalg.norm(Tmat_l)
Exemplo n.º 3
0
def pwe_to_swe_conversion(pwe, l_max, m_max, reference_point):
    """Convert plane wave expansion object to a spherical wave expansion object.

    Args:
        pwe (PlaneWaveExpansion):   Plane wave expansion to be converted
        l_max (int):                Maximal multipole degree of spherical wave expansion
        m_max (int):                Maximal multipole order of spherical wave expansion
        reference_point (list):     Coordinates of reference point in the format [x, y, z]

    Returns:
        SphericalWaveExpansion object.
    """

    if reference_point[2] < pwe.lower_z or reference_point[2] > pwe.upper_z:
        raise ValueError('reference point not inside domain of pwe validity')

    swe = fex.SphericalWaveExpansion(k=pwe.k, l_max=l_max, m_max=m_max, kind='regular', 
                                 reference_point=reference_point, lower_z=pwe.lower_z, 
                                 upper_z=pwe.upper_z)
    kpgrid = pwe.k_parallel_grid()
    agrid = pwe.azimuthal_angle_grid()
    kx = kpgrid * np.cos(agrid)
    ky = kpgrid * np.sin(agrid)
    kz = pwe.k_z_grid()
    kzvec = pwe.k_z()

    kvec = np.array([kx, ky, kz])
    rswe_mn_rpwe = np.array(reference_point) - np.array(pwe.reference_point)

    # phase factor for the translation of the reference point from rvec_iS to rvec_S
    ejkriSS = np.exp(1j * (kvec[0] * rswe_mn_rpwe[0] + kvec[1] * rswe_mn_rpwe[1] + kvec[2] * rswe_mn_rpwe[2]))

    # phase factor times pwe coefficients
    gejkriSS = pwe.coefficients * ejkriSS[None, :, :]  # indices: pol, jk, ja
    
    ct = kzvec / pwe.k
    st = pwe.k_parallel / pwe.k
    plm_list, pilm_list, taulm_list = mathfunc.legendre_normalized(ct, st, l_max)

    for m in range(-m_max, m_max + 1):
        emjma_geijkriSS = np.exp(-1j * m * pwe.azimuthal_angles)[None, None, :] * gejkriSS
        for l in range(max(1, abs(m)), l_max + 1):
            for tau in range(2):
                ak_integrand = np.zeros(kpgrid.shape, dtype=complex)
                for pol in range(2):
                    Bdag = transformation_coefficients_vwf(tau, l, m, pol=pol, pilm_list=pilm_list,
                                                               taulm_list=taulm_list, kz=kzvec, dagger=True)
                    ak_integrand += Bdag[:, None] * emjma_geijkriSS[pol, :, :]
                if len(pwe.k_parallel) > 1:
                    an = np.trapz(np.trapz(ak_integrand, pwe.azimuthal_angles) * pwe.k_parallel, pwe.k_parallel) * 4
                else:
                    an = ak_integrand * 4
                swe.coefficients[flds.multi_to_single_index(tau, l, m, swe.l_max, swe.m_max)] = np.squeeze(an)
    return swe
Exemplo n.º 4
0
    def testMulti2SingleSTLM(self):
        idcs = []
        lmax = 5
        mmax = 5
        count = 0
        for tau in range(2):
            for l in range(1, lmax + 1):
                for m in range(-l, l + 1):
                    idcs.append(
                        flds.multi_to_single_index(tau=tau,
                                                   l=l,
                                                   m=m,
                                                   l_max=lmax,
                                                   m_max=mmax))
                    count += 1

        self.assertEqual(idcs, list(range(len(idcs))))

        ind_num = flds.blocksize(lmax, mmax)
        self.assertEqual(count, ind_num)

        idcs = []
        lmax = 6
        mmax = 3
        count = 0
        for tau in range(2):
            for l in range(1, lmax + 1):
                mlim = min(l, mmax)
                for m in range(-mlim, mlim + 1):
                    idcs.append(
                        flds.multi_to_single_index(tau=tau,
                                                   l=l,
                                                   m=m,
                                                   l_max=lmax,
                                                   m_max=mmax))
                    count += 1
        self.assertEqual(idcs, list(range(len(idcs))))

        ind_num = flds.blocksize(lmax, mmax)
        self.assertEqual(count, ind_num)
Exemplo n.º 5
0
    def testTmatrix(self):
        t = tmt.t_matrix_sphere(omega * n_medium, omega * n_particle, radius, lmax, mmax)
        n = flds.multi_to_single_index(tau, l, m, lmax, mmax)
        mie = tmt.mie_coefficient(tau, l, omega * n_medium, omega * n_particle, radius)
        assert t[n, n] == mie

        sphere1 = smuthi.particles.Sphere(radius=100, refractive_index=3, position=[100, 200, 300], l_max=lmax, m_max=mmax)
        sphere2 = smuthi.particles.Sphere(radius=100, refractive_index=3, position=[200, -200, 200], l_max=lmax, m_max=mmax)
        sphere3 = smuthi.particles.Sphere(radius=200, refractive_index=2+0.2j, position=[200,-200,200], l_max=lmax,
                                          m_max=mmax)

        t2 = tmt.t_matrix(vacuum_wavelength=550, n_medium=n_medium, particle=sphere1)
        t3 = tmt.t_matrix_sphere(2*np.pi/550 * n_medium, 2*np.pi/550 * 3, 100, lmax, mmax)
        np.testing.assert_allclose(t2, t3)
Exemplo n.º 6
0
    def index(self, i, tau, l, m):
        r"""
        Args:
            i (int):    particle number
            tau (int):    spherical polarization index
            l (int):    multipole degree
            m (int):    multipole order

        Returns:
            Position in a system vector that corresponds to the :math:`(\tau, l, m)` coefficient of the i-th particle.
        """
        blocksizes = [
            flds.blocksize(particle.l_max, particle.m_max)
            for particle in self.particle_list[:i]
        ]
        return sum(blocksizes) + flds.multi_to_single_index(
            tau, l, m, self.particle_list[i].l_max,
            self.particle_list[i].m_max)
Exemplo n.º 7
0
def internal_field_piecewise_expansion(vacuum_wavelength, particle_list, layer_system):
    """Compute a piecewise field expansion of the internal field of spheres.

    Args:
        vacuum_wavelength (float):                  vacuum wavelength
        particle_list (list):                       list of smuthi.particles.Particle objects
        layer_system (smuthi.layers.LayerSystem):   stratified medium

    Returns:
        internal field as smuthi.field_expansion.PiecewiseFieldExpansion object

    """
    intfld = fldex.PiecewiseFieldExpansion()

    for particle in particle_list:
        if type(particle).__name__ == 'Sphere':
            i_part = layer_system.layer_number(particle.position[2])
            k_medium = flds.angular_frequency(vacuum_wavelength) * layer_system.refractive_indices[i_part]
            k_particle = flds.angular_frequency(vacuum_wavelength) * particle.refractive_index

            internal_field = fldex.SphericalWaveExpansion(
                k_particle,
                l_max=particle.l_max,
                m_max=particle.m_max,
                kind='regular',
                reference_point=particle.position)

            internal_field.validity_conditions.append(particle.is_inside)

            for tau in range(2):
                for l in range(1, particle.l_max+1):
                    for m in range(-l, l+1):
                        n = flds.multi_to_single_index(tau, l, m, particle.l_max, particle.m_max)
                        b_to_c = (tmt.internal_mie_coefficient(tau, l, k_medium, k_particle, particle.radius)
                                  / tmt.mie_coefficient(tau, l, k_medium, k_particle, particle.radius))
                        internal_field.coefficients[n] = particle.scattered_field.coefficients[n] * b_to_c

            intfld.expansion_list.append(internal_field)
            particle.internal_field = internal_field

    return intfld
Exemplo n.º 8
0
def t_matrix_sphere(k_medium, k_particle, radius, l_max, m_max):
    """T-matrix of a spherical scattering object.

    Args:
        k_medium (float or complex):            Wavenumber in surrounding medium (inverse length unit)
        k_particle (float or complex):          Wavenumber inside sphere (inverse length unit)
        radius (float):                         Radius of sphere (length unit)
        l_max (int):                            Maximal multipole degree
        m_max (int):                            Maximal multipole order

    Returns:
         T-matrix as ndarray
    """
    t = np.zeros((flds.blocksize(l_max, m_max), flds.blocksize(l_max, m_max)),
                 dtype=complex)
    for tau in range(2):
        for m in range(-m_max, m_max + 1):
            for l in range(max(1, abs(m)), l_max + 1):
                n = flds.multi_to_single_index(tau, l, m, l_max, m_max)
                t[n, n] = mie_coefficient(tau, l, k_medium, k_particle, radius)
    return t
Exemplo n.º 9
0
    def __init__(self,
                 vacuum_wavelength,
                 particle_list,
                 layer_system,
                 k_parallel='default',
                 resolution=None,
                 interpolator_kind='linear'):

        z_list = [particle.position[2] for particle in particle_list]
        assert z_list.count(z_list[0]) == len(z_list)

        CouplingMatrixRadialLookup.__init__(self, vacuum_wavelength,
                                            particle_list, layer_system,
                                            k_parallel, resolution)

        x_array = np.array(
            [particle.position[0] for particle in particle_list])
        y_array = np.array(
            [particle.position[1] for particle in particle_list])

        self.particle_rho_array = np.sqrt(
            (x_array[:, None] - x_array[None, :])**2 +
            (y_array[:, None] - y_array[None, :])**2)
        self.particle_phi_array = np.arctan2(
            y_array[:, None] - y_array[None, :],
            x_array[:, None] - x_array[None, :])

        # contains for each n all positions in the large system arrays that correspond to n:
        self.system_vector_index_list = [[] for i in range(self.blocksize)]

        # same size as system_vector_index_list, contains the according particle numbers:
        self.particle_number_list = [[] for i in range(self.blocksize)]
        self.m_list = [None for i in range(self.blocksize)]
        for i, particle in enumerate(particle_list):
            for m in range(-particle.m_max, particle.m_max + 1):
                for l in range(max(1, abs(m)), particle.l_max + 1):
                    for tau in range(2):
                        n_lookup = flds.multi_to_single_index(tau=tau,
                                                              l=l,
                                                              m=m,
                                                              l_max=self.l_max,
                                                              m_max=self.m_max)
                        self.system_vector_index_list[n_lookup].append(
                            self.index(i, tau, l, m))
                        self.particle_number_list[n_lookup].append(i)
                        self.m_list[n_lookup] = m
        for n in range(self.blocksize):
            self.system_vector_index_list[n] = np.array(
                self.system_vector_index_list[n])
            self.particle_number_list[n] = np.array(
                self.particle_number_list[n])

        lookup = [[None for i in range(self.blocksize)]
                  for i2 in range(self.blocksize)]
        for n1 in range(self.blocksize):
            for n2 in range(self.blocksize):
                lookup[n1][n2] = scipy.interpolate.interp1d(
                    x=self.radial_distance_array,
                    y=self.lookup_table[:, n1, n2],
                    kind=interpolator_kind,
                    axis=-1,
                    assume_sorted=True)

        def matvec(in_vec):
            out_vec = np.zeros(shape=in_vec.shape, dtype=complex)
            for n1 in range(self.blocksize):
                i1 = self.particle_number_list[n1]
                idx1 = self.system_vector_index_list[n1]
                m1 = self.m_list[n1]
                for n2 in range(self.blocksize):
                    i2 = self.particle_number_list[n2]
                    idx2 = self.system_vector_index_list[n2]
                    m2 = self.m_list[n2]
                    rho = self.particle_rho_array[i1[:, None], i2[None, :]]
                    phi = self.particle_phi_array[i1[:, None], i2[None, :]]
                    M = lookup[n1][n2](rho)
                    M = M * np.exp(1j * (m2 - m1) * phi)
                    out_vec[idx1] += M.dot(in_vec[idx2])
            return out_vec

        self.linear_operator = scipy.sparse.linalg.LinearOperator(
            shape=self.shape, matvec=matvec, dtype=complex)
Exemplo n.º 10
0
    def __init__(self,
                 vacuum_wavelength,
                 particle_list,
                 layer_system,
                 k_parallel='default',
                 resolution=None,
                 cuda_blocksize=None,
                 interpolator_kind='linear'):

        if cuda_blocksize is None:
            cuda_blocksize = cu.default_blocksize

        CouplingMatrixRadialLookup.__init__(self, vacuum_wavelength,
                                            particle_list, layer_system,
                                            k_parallel, resolution)

        sys.stdout.write('Prepare CUDA kernel and device lookup data ... ')
        sys.stdout.flush()
        start_time = time.time()

        if interpolator_kind == 'linear':
            coupling_source = cusrc.linear_radial_lookup_source % (
                self.blocksize, self.shape[0],
                self.radial_distance_array.min(), resolution)
        elif interpolator_kind == 'cubic':
            coupling_source = cusrc.cubic_radial_lookup_source % (
                self.blocksize, self.shape[0],
                self.radial_distance_array.min(), resolution)

        coupling_function = cu.SourceModule(coupling_source).get_function(
            "coupling_kernel")

        n_lookup_array = np.zeros(self.shape[0], dtype=np.uint32)
        m_particle_array = np.zeros(self.shape[0], dtype=np.float32)
        x_array = np.zeros(self.shape[0], dtype=np.float32)
        y_array = np.zeros(self.shape[0], dtype=np.float32)

        i_particle = 0
        for i, particle in enumerate(particle_list):
            for m in range(-particle.m_max, particle.m_max + 1):
                for l in range(max(1, abs(m)), particle.l_max + 1):
                    for tau in range(2):
                        # idx = self.index(i, tau, l, m)
                        i_taulm = flds.multi_to_single_index(
                            tau, l, m, particle.l_max, particle.m_max)
                        idx = i_particle + i_taulm

                        n_lookup_array[idx] = flds.multi_to_single_index(
                            tau, l, m, self.l_max, self.m_max)
                        m_particle_array[idx] = m

                        # scale the x and y position to the lookup resolution:
                        x_array[idx] = particle.position[0]
                        y_array[idx] = particle.position[1]

            i_particle += flds.blocksize(particle.l_max, particle.m_max)

        # lookup as numpy array in required shape
        re_lookup = self.lookup_table.real.astype(np.float32)
        im_lookup = self.lookup_table.imag.astype(np.float32)

        # transfer data to gpu
        n_lookup_array_d = cu.gpuarray.to_gpu(n_lookup_array)
        m_particle_array_d = cu.gpuarray.to_gpu(m_particle_array)
        x_array_d = cu.gpuarray.to_gpu(x_array)
        y_array_d = cu.gpuarray.to_gpu(y_array)
        re_lookup_d = cu.gpuarray.to_gpu(re_lookup)
        im_lookup_d = cu.gpuarray.to_gpu(im_lookup)

        sys.stdout.write('done | elapsed: ' +
                         str(int(time.time() - start_time)) + 's\n')
        sys.stdout.flush()

        cuda_gridsize = (self.shape[0] + cuda_blocksize - 1) // cuda_blocksize

        def matvec(in_vec):
            re_in_vec_d = cu.gpuarray.to_gpu(np.float32(in_vec.real))
            im_in_vec_d = cu.gpuarray.to_gpu(np.float32(in_vec.imag))
            re_result_d = cu.gpuarray.zeros(in_vec.shape, dtype=np.float32)
            im_result_d = cu.gpuarray.zeros(in_vec.shape, dtype=np.float32)
            coupling_function(n_lookup_array_d.gpudata,
                              m_particle_array_d.gpudata,
                              x_array_d.gpudata,
                              y_array_d.gpudata,
                              re_lookup_d.gpudata,
                              im_lookup_d.gpudata,
                              re_in_vec_d.gpudata,
                              im_in_vec_d.gpudata,
                              re_result_d.gpudata,
                              im_result_d.gpudata,
                              block=(cuda_blocksize, 1, 1),
                              grid=(cuda_gridsize, 1))
            return re_result_d.get() + 1j * im_result_d.get()

        self.linear_operator = scipy.sparse.linalg.LinearOperator(
            shape=self.shape, matvec=matvec, dtype=complex)
Exemplo n.º 11
0
    def __init__(self,
                 vacuum_wavelength,
                 particle_list,
                 layer_system,
                 k_parallel='default',
                 resolution=None,
                 interpolator_kind='cubic'):

        if interpolator_kind == 'cubic':
            interpolation_order = 3
        else:
            interpolation_order = 1

        CouplingMatrixVolumeLookup.__init__(self, vacuum_wavelength,
                                            particle_list, layer_system,
                                            k_parallel, resolution)

        x_array = np.array(
            [particle.position[0] for particle in particle_list])
        y_array = np.array(
            [particle.position[1] for particle in particle_list])
        z_array = np.array(
            [particle.position[2] for particle in particle_list])

        self.particle_rho_array = np.sqrt(
            (x_array[:, None] - x_array[None, :])**2 +
            (y_array[:, None] - y_array[None, :])**2)
        self.particle_phi_array = np.arctan2(
            y_array[:, None] - y_array[None, :],
            x_array[:, None] - x_array[None, :])
        self.particle_sz_array = z_array[:, None] + z_array[None, :]
        self.particle_dz_array = z_array[:, None] - z_array[None, :]

        # contains for each n all positions in the large system arrays that correspond to n:
        self.system_vector_index_list = [[] for i in range(self.blocksize)]

        # same size as system_vector_index_list, contains the according particle numbers:
        self.particle_number_list = [[] for i in range(self.blocksize)]
        self.m_list = [None for i in range(self.blocksize)]
        for i, particle in enumerate(particle_list):
            for m in range(-particle.m_max, particle.m_max + 1):
                for l in range(max(1, abs(m)), particle.l_max + 1):
                    for tau in range(2):
                        n_lookup = flds.multi_to_single_index(tau=tau,
                                                              l=l,
                                                              m=m,
                                                              l_max=self.l_max,
                                                              m_max=self.m_max)
                        self.system_vector_index_list[n_lookup].append(
                            self.index(i, tau, l, m))
                        self.particle_number_list[n_lookup].append(i)
                        self.m_list[n_lookup] = m
        for n in range(self.blocksize):
            self.system_vector_index_list[n] = np.array(
                self.system_vector_index_list[n])
            self.particle_number_list[n] = np.array(
                self.particle_number_list[n])

        self.lookup_plus_real = [[None for i in range(self.blocksize)]
                                 for i2 in range(self.blocksize)]
        self.lookup_plus_imag = [[None for i in range(self.blocksize)]
                                 for i2 in range(self.blocksize)]
        self.lookup_minus_real = [[None for i in range(self.blocksize)]
                                  for i2 in range(self.blocksize)]
        self.lookup_minus_imag = [[None for i in range(self.blocksize)]
                                  for i2 in range(self.blocksize)]
        for n1 in range(self.blocksize):
            for n2 in range(self.blocksize):
                self.lookup_plus_real[n1][
                    n2] = scipy.interpolate.RectBivariateSpline(
                        x=self.rho_array,
                        y=self.sum_z_array,
                        z=self.lookup_table_plus[:, :, n1, n2].real,
                        kx=interpolation_order,
                        ky=interpolation_order)
                self.lookup_plus_imag[n1][
                    n2] = scipy.interpolate.RectBivariateSpline(
                        x=self.rho_array,
                        y=self.sum_z_array,
                        z=self.lookup_table_plus[:, :, n1, n2].imag,
                        kx=interpolation_order,
                        ky=interpolation_order)
                self.lookup_minus_real[n1][
                    n2] = scipy.interpolate.RectBivariateSpline(
                        x=self.rho_array,
                        y=self.diff_z_array,
                        z=self.lookup_table_minus[:, :, n1, n2].real,
                        kx=interpolation_order,
                        ky=interpolation_order)
                self.lookup_minus_imag[n1][
                    n2] = scipy.interpolate.RectBivariateSpline(
                        x=self.rho_array,
                        y=self.diff_z_array,
                        z=self.lookup_table_minus[:, :, n1, n2].imag,
                        kx=interpolation_order,
                        ky=interpolation_order)

        def matvec(in_vec):
            out_vec = np.zeros(shape=in_vec.shape, dtype=complex)
            for n1 in range(self.blocksize):
                i1 = self.particle_number_list[n1]
                idx1 = self.system_vector_index_list[n1]
                m1 = self.m_list[n1]
                for n2 in range(self.blocksize):
                    i2 = self.particle_number_list[n2]
                    idx2 = self.system_vector_index_list[n2]
                    m2 = self.m_list[n2]
                    rho = self.particle_rho_array[i1[:, None], i2[None, :]]
                    phi = self.particle_phi_array[i1[:, None], i2[None, :]]
                    sz = self.particle_sz_array[i1[:, None], i2[None, :]]
                    dz = self.particle_dz_array[i1[:, None], i2[None, :]]
                    Mpl = self.lookup_plus_real[n1][n2].ev(
                        rho,
                        sz) + 1j * self.lookup_plus_imag[n1][n2].ev(rho, sz)
                    Mmn = self.lookup_minus_real[n1][n2].ev(
                        rho,
                        dz) + 1j * self.lookup_minus_imag[n1][n2].ev(rho, dz)
                    M = (Mpl + Mmn) * np.exp(1j * (m2 - m1) * phi)
                    out_vec[idx1] += M.dot(in_vec[idx2])
            return out_vec

        self.linear_operator = scipy.sparse.linalg.LinearOperator(
            shape=self.shape, matvec=matvec, dtype=complex)
Exemplo n.º 12
0
def taxsym_read_tmatrix(filename, l_max, m_max):
    """Export TAXSYM.f90 output to SMUTHI T-matrix.

    .. todo:: feedback to adapt particle m_max to nfmds m_max

    Args:
        filename (str): Name of the file containing the T-matrix output of TAXSYM.f90
        l_max (int):    Maximal multipole degree
        m_max (int):    Maximal multipole order

    Returns:
        T-matrix as numpy.ndarray
    """

    with open(nfmds.nfmds_folder + '/TMATFILES/Info' + filename,
              'r') as info_file:
        info_file_lines = info_file.readlines()

    assert 'The scatterer is an axisymmetric particle' in ' '.join(
        info_file_lines)

    for line in info_file_lines:
        if line.split()[0:4] == ['-', 'maximum', 'expansion', 'order,']:
            n_rank = int(line.split()[-1][0:-1])

        if line.split()[0:5] == ['-', 'number', 'of', 'azimuthal', 'modes,']:
            m_rank = int(line.split()[-1][0:-1])

    with open(nfmds.nfmds_folder + '/TMATFILES/' + filename, 'r') as tmat_file:
        tmat_lines = tmat_file.readlines()

    t_nfmds = [[]]
    column_index = 0
    for line in tmat_lines[3:]:
        split_line = line.split()
        for i_entry in range(int(len(split_line) / 2)):
            if column_index == 2 * n_rank:
                t_nfmds.append([])
                column_index = 0
            t_nfmds[-1].append(
                complex(split_line[2 * i_entry]) +
                1j * complex(split_line[2 * i_entry + 1]))
            column_index += 1

    t_matrix = np.zeros(
        (flds.blocksize(l_max, m_max), flds.blocksize(l_max, m_max)),
        dtype=complex)

    for m in range(-m_max, m_max + 1):
        n_max_nfmds = n_rank - max(1, abs(m)) + 1
        for tau1 in range(2):
            for l1 in range(max(1, abs(m)), l_max + 1):
                n1 = flds.multi_to_single_index(tau=tau1,
                                                l=l1,
                                                m=m,
                                                l_max=l_max,
                                                m_max=m_max)
                l1_nfmds = l1 - max(1, abs(m))
                n1_nfmds = 2 * n_rank * abs(m) + tau1 * n_max_nfmds + l1_nfmds
                for tau2 in range(2):
                    for l2 in range(max(1, abs(m)), l_max + 1):
                        n2 = flds.multi_to_single_index(tau=tau2,
                                                        l=l2,
                                                        m=m,
                                                        l_max=l_max,
                                                        m_max=m_max)
                        l2_nfmds = l2 - max(1, abs(m))
                        n2_nfmds = tau2 * n_max_nfmds + l2_nfmds
                        if abs(m) <= m_rank:
                            if m >= 0:
                                t_matrix[n1, n2] = t_nfmds[n1_nfmds][n2_nfmds]
                            else:
                                t_matrix[n1,
                                         n2] = t_nfmds[n1_nfmds][n2_nfmds] * (
                                             -1)**(tau1 + tau2)

    return t_matrix
Exemplo n.º 13
0
def direct_coupling_block_pvwf_mediated(vacuum_wavelength, receiving_particle,
                                        emitting_particle, layer_system,
                                        k_parallel):
    """Direct particle coupling matrix :math:`W` for two particles (via plane vector wave functions).
    For details, see: 
    Dominik Theobald et al., Phys. Rev. A 96, 033822, DOI: 10.1103/PhysRevA.96.033822 or arXiv:1708.04808 


    Args:
        vacuum_wavelength (float):                          Vacuum wavelength :math:`\lambda` (length unit)
        receiving_particle (smuthi.particles.Particle):     Particle that receives the scattered field
        emitting_particle (smuthi.particles.Particle):      Particle that emits the scattered field
        layer_system (smuthi.layers.LayerSystem):           Stratified medium in which the coupling takes place
        k_parallel (numpy.array):                           In-plane wavenumber for plane wave expansion

    Returns:
        Direct coupling matrix block (numpy array).
    """
    if type(receiving_particle).__name__ != 'Spheroid' or type(
            emitting_particle).__name__ != 'Spheroid':
        raise NotImplementedError(
            'plane wave coupling currently implemented only for spheroids')

    lmax1 = receiving_particle.l_max
    mmax1 = receiving_particle.m_max
    assert lmax1 == mmax1, 'PVWF coupling requires lmax == mmax for each particle.'
    lmax2 = emitting_particle.l_max
    mmax2 = emitting_particle.m_max
    assert lmax2 == mmax2, 'PVWF coupling requires lmax == mmax for each particle.'
    lmax = max([lmax1, lmax2])
    m_max = max([mmax1, mmax2])
    blocksize1 = flds.blocksize(lmax1, mmax1)
    blocksize2 = flds.blocksize(lmax2, mmax2)

    n_medium = layer_system.refractive_indices[layer_system.layer_number(
        receiving_particle.position[2])]

    # finding the orientation of a plane separating the spheroids
    _, _, alpha, beta = spheroids_closest_points(
        emitting_particle.semi_axis_a, emitting_particle.semi_axis_c,
        emitting_particle.position, emitting_particle.euler_angles,
        receiving_particle.semi_axis_a, receiving_particle.semi_axis_c,
        receiving_particle.position, receiving_particle.euler_angles)

    # positions
    r1 = np.array(receiving_particle.position)
    r2 = np.array(emitting_particle.position)
    r21_lab = r1 - r2  # laboratory coordinate system

    # distance vector in rotated coordinate system
    r21_rot = np.dot(
        np.dot([[np.cos(beta), 0, np.sin(beta)], [0, 1, 0],
                [-np.sin(beta), 0, np.cos(beta)]],
               [[np.cos(alpha), -np.sin(alpha), 0],
                [np.sin(alpha), np.cos(alpha), 0], [0, 0, 1]]), r21_lab)
    rho21 = (r21_rot[0]**2 + r21_rot[1]**2)**0.5
    phi21 = np.arctan2(r21_rot[1], r21_rot[0])
    z21 = r21_rot[2]

    # wavenumbers
    omega = flds.angular_frequency(vacuum_wavelength)
    k = omega * n_medium
    kz = flds.k_z(k_parallel=k_parallel,
                  vacuum_wavelength=vacuum_wavelength,
                  refractive_index=n_medium)
    if z21 < 0:
        kz_var = -kz
    else:
        kz_var = kz

    # Bessel lookup
    bessel_list = []
    for dm in range(mmax1 + mmax2 + 1):
        bessel_list.append(scipy.special.jn(dm, k_parallel * rho21))

    # legendre function lookups
    ct = kz_var / k
    st = k_parallel / k
    _, pilm_list, taulm_list = sf.legendre_normalized(ct, st, lmax)

    # initialize result
    w = np.zeros((blocksize1, blocksize2), dtype=complex)

    # prefactor
    const_arr = k_parallel / (kz * k) * np.exp(1j * (kz_var * z21))

    for m1 in range(-mmax1, mmax1 + 1):
        for m2 in range(-mmax2, mmax2 + 1):
            jmm_eimphi_bessel = 4 * 1j**abs(m2 - m1) * np.exp(
                1j * phi21 * (m2 - m1)) * bessel_list[abs(m2 - m1)]
            prefactor = const_arr * jmm_eimphi_bessel
            for l1 in range(max(1, abs(m1)), lmax1 + 1):
                for l2 in range(max(1, abs(m2)), lmax2 + 1):
                    for tau1 in range(2):
                        n1 = flds.multi_to_single_index(
                            tau1, l1, m1, lmax1, mmax1)
                        for tau2 in range(2):
                            n2 = flds.multi_to_single_index(
                                tau2, l2, m2, lmax2, mmax2)
                            for pol in range(2):
                                B_dag = trf.transformation_coefficients_vwf(
                                    tau1,
                                    l1,
                                    m1,
                                    pol,
                                    pilm_list=pilm_list,
                                    taulm_list=taulm_list,
                                    dagger=True)
                                B = trf.transformation_coefficients_vwf(
                                    tau2,
                                    l2,
                                    m2,
                                    pol,
                                    pilm_list=pilm_list,
                                    taulm_list=taulm_list,
                                    dagger=False)
                                integrand = prefactor * B * B_dag
                                w[n1, n2] += np.trapz(integrand, k_parallel)

    rot_mat_1 = trf.block_rotation_matrix_D_svwf(lmax1, mmax1, 0, beta, alpha)
    rot_mat_2 = trf.block_rotation_matrix_D_svwf(lmax2, mmax2, -alpha, -beta,
                                                 0)

    return np.dot(np.dot(np.transpose(rot_mat_1), w), np.transpose(rot_mat_2))
Exemplo n.º 14
0
def direct_coupling_block(vacuum_wavelength, receiving_particle,
                          emitting_particle, layer_system):
    """Direct particle coupling matrix :math:`W` for two particles. This routine is explicit, but slow.

    Args:
        vacuum_wavelength (float):                          Vacuum wavelength :math:`\lambda` (length unit)
        receiving_particle (smuthi.particles.Particle):     Particle that receives the scattered field
        emitting_particle (smuthi.particles.Particle):      Particle that emits the scattered field
        layer_system (smuthi.layers.LayerSystem):           Stratified medium in which the coupling takes place

    Returns:
        Direct coupling matrix block as numpy array.
    """
    omega = flds.angular_frequency(vacuum_wavelength)

    # index specs
    lmax1 = receiving_particle.l_max
    mmax1 = receiving_particle.m_max
    lmax2 = emitting_particle.l_max
    mmax2 = emitting_particle.m_max
    blocksize1 = flds.blocksize(lmax1, mmax1)
    blocksize2 = flds.blocksize(lmax2, mmax2)

    # initialize result
    w = np.zeros((blocksize1, blocksize2), dtype=complex)

    # check if particles are in same layer
    rS1 = receiving_particle.position
    rS2 = emitting_particle.position
    iS1 = layer_system.layer_number(rS1[2])
    iS2 = layer_system.layer_number(rS2[2])
    if iS1 == iS2 and not emitting_particle == receiving_particle:
        k = omega * layer_system.refractive_indices[iS1]
        dx = rS1[0] - rS2[0]
        dy = rS1[1] - rS2[1]
        dz = rS1[2] - rS2[2]
        d = np.sqrt(dx**2 + dy**2 + dz**2)
        cos_theta = dz / d
        sin_theta = np.sqrt(dx**2 + dy**2) / d
        phi = np.arctan2(dy, dx)

        # spherical functions
        bessel_h = [
            sf.spherical_hankel(n, k * d) for n in range(lmax1 + lmax2 + 1)
        ]
        legendre, _, _ = sf.legendre_normalized(cos_theta, sin_theta,
                                                lmax1 + lmax2)

        # the particle coupling operator is the transpose of the SVWF translation operator
        # therefore, (l1,m1) and (l2,m2) are interchanged:
        for m1 in range(-mmax1, mmax1 + 1):
            for m2 in range(-mmax2, mmax2 + 1):
                eimph = np.exp(1j * (m2 - m1) * phi)
                for l1 in range(max(1, abs(m1)), lmax1 + 1):
                    for l2 in range(max(1, abs(m2)), lmax2 + 1):
                        A, B = complex(0), complex(0)
                        for ld in range(max(abs(l1 - l2), abs(m1 - m2)), l1 +
                                        l2 + 1):  # if ld<abs(m1-m2) then P=0
                            a5, b5 = trf.ab5_coefficients(l2, m2, l1, m1, ld)
                            A += a5 * bessel_h[ld] * legendre[ld][abs(m1 - m2)]
                            B += b5 * bessel_h[ld] * legendre[ld][abs(m1 - m2)]
                        A, B = eimph * A, eimph * B
                        for tau1 in range(2):
                            n1 = flds.multi_to_single_index(
                                tau1, l1, m1, lmax1, mmax1)
                            for tau2 in range(2):
                                n2 = flds.multi_to_single_index(
                                    tau2, l2, m2, lmax2, mmax2)
                                if tau1 == tau2:
                                    w[n1, n2] = A
                                else:
                                    w[n1, n2] = B

    return w