Beispiel #1
0
    def spherical_wave_expansion(self, particle, layer_system):
        """Regular spherical wave expansion of the dipole collection including layer system response, at the locations 
        of the particles. If self.compute_swe_by_pwe is True, use the dipole collection plane wave expansion, otherwise
        use the individual dipoles spherical_wave_expansion method.

        Args:
            particle (smuthi.particles.Particle):    particle relative to which the swe is computed
            layer_system (smuthi.layer.LayerSystem): stratified medium

        Returns:
            regular smuthi.field_expansion.SphericalWaveExpansion object
        """
        # compute by pwe?
        if self.compute_swe_by_pwe and not any(
                layer_system.layer_number(particle.position[2]) == np.array([
                    layer_system.layer_number(dip.position[2])
                    for dip in self.dipole_list
                ])):
            # (make sure the particle is not in the same layer as one of the dipoles)
            return InitialPropagatingWave.spherical_wave_expansion(
                self, particle, layer_system)

        # otherwise, compute by swe of virtual particles
        k = self.angular_frequency() * layer_system.refractive_indices[
            layer_system.layer_number(particle.position[2])]
        swe = fldex.SphericalWaveExpansion(k=k,
                                           l_max=particle.l_max,
                                           m_max=particle.m_max,
                                           kind='regular',
                                           reference_point=particle.position)
        for dipole in self.dipole_list:
            swe = swe + dipole.spherical_wave_expansion(particle, layer_system)
        return swe
Beispiel #2
0
    def spherical_wave_expansion(self, particle, layer_system):
        """Regular spherical wave expansion of the wave including layer system response, at the locations of the
        particles.

        Args:
            particle (smuthi.particles.Particle):    particle relative to which the swe is computed
            layer_system (smuthi.layer.LayerSystem): stratified medium

        Returns:
            regular smuthi.field_expansion.SphericalWaveExpansion object
        """
        virtual_particle = part.Particle(position=self.position,
                                         l_max=1,
                                         m_max=1)
        wd = pc.direct_coupling_block(vacuum_wavelength=self.vacuum_wavelength,
                                      receiving_particle=particle,
                                      emitting_particle=virtual_particle,
                                      layer_system=layer_system)
        wr = pc.layer_mediated_coupling_block(
            vacuum_wavelength=self.vacuum_wavelength,
            receiving_particle=particle,
            emitting_particle=virtual_particle,
            layer_system=layer_system,
            k_parallel=self.k_parallel)
        k = self.angular_frequency() * layer_system.refractive_indices[
            layer_system.layer_number(particle.position[2])]
        swe = fldex.SphericalWaveExpansion(k=k,
                                           l_max=particle.l_max,
                                           m_max=particle.m_max,
                                           kind='regular',
                                           reference_point=particle.position)
        swe.coefficients = np.dot(
            wd + wr,
            self.outgoing_spherical_wave_expansion(layer_system).coefficients)
        return swe
Beispiel #3
0
    def outgoing_spherical_wave_expansion(self, layer_system):
        """The dipole field as an expansion in spherical vector wave functions.

        Args:
            layer_system (smuthi.layers.LayerSystem):   stratified medium

        Returns:
            outgoing smuthi.field_expansion.SphericalWaveExpansion object
        """
        laynum = layer_system.layer_number(self.position[2])
        k = layer_system.refractive_indices[laynum] * self.angular_frequency()
        swe_out = fldex.SphericalWaveExpansion(
            k=k,
            l_max=1,
            m_max=1,
            kind='outgoing',
            reference_point=self.position,
            lower_z=layer_system.lower_zlimit(laynum),
            upper_z=layer_system.upper_zlimit(laynum))
        l = 1
        for tau in range(2):
            for m in range(-1, 2):
                ex, ey, ez = vwf.spherical_vector_wave_function(
                    0, 0, 0, k, 1, tau, l, -m)
                b = 1j * k / np.pi * 1j * self.angular_frequency() * (
                    ex * self.current()[0] + ey * self.current()[1] +
                    ez * self.current()[2])
                swe_out.coefficients[fldex.multi_to_single_index(
                    tau, l, m, 1, 1)] = b

        return swe_out
Beispiel #4
0
    def dissipated_power(self,
                         particle_list,
                         layer_system,
                         show_progress=True):
        r"""Compute the power that the dipole feeds into the system.

        It is computed according to

        .. math::
            P = P_0 + \frac{\omega}{2} \mathrm{Im} (\mathbf{\mu}^* \cdot \mathbf{E}(\mathbf{r}_D))

        where :math:`P_0` is the power that the dipole would feed into an infinte homogeneous medium with the same
        refractive index as the layer that contains the dipole, :math:`\mathbf{r}_D` is the location of the dipole,
        :math:`\omega` is the angular frequency, :math:`\mathbf{\mu}` is the dipole moment and :math:`\mathbf{E}`
        includes the reflections of the dipole field from the layer interfaces, as well as the scattered field from all
        particles.

        Args:
            particle_list (list of smuthi.particles.Particle objects): scattering particles
            layer_system (smuthi.layers.LayerSystem):                  stratified medium
            show_progress (bool):                                      if true, display progress
            
        Returns:
            dissipated power as float
        """

        k = layer_system.wavenumber(
            layer_system.layer_number(self.position[2]),
            self.vacuum_wavelength)
        virtual_particle = part.Particle(position=self.position,
                                         l_max=1,
                                         m_max=1)
        scattered_field_swe = fldex.SphericalWaveExpansion(
            k=k,
            l_max=1,
            m_max=1,
            kind='regular',
            reference_point=self.position)

        if show_progress:
            iterator = tqdm(
                particle_list,
                desc='Dipole dissipated power   ',
                file=sys.stdout,
                bar_format=
                '{l_bar}{bar}| elapsed: {elapsed} remaining: {remaining}')
        else:
            iterator = particle_list

        for particle in iterator:
            wd = pc.direct_coupling_block(
                vacuum_wavelength=self.vacuum_wavelength,
                receiving_particle=virtual_particle,
                emitting_particle=particle,
                layer_system=layer_system)

            wr = pc.layer_mediated_coupling_block(
                vacuum_wavelength=self.vacuum_wavelength,
                receiving_particle=virtual_particle,
                emitting_particle=particle,
                layer_system=layer_system,
                k_parallel=self.k_parallel)

            scattered_field_swe.coefficients += np.dot(
                wd + wr, particle.scattered_field.coefficients)

        e_x_scat, e_y_scat, e_z_scat = scattered_field_swe.electric_field(
            x=self.position[0], y=self.position[1], z=self.position[2])

        e_x_in, e_y_in, e_z_in = self.electric_field(
            x=self.position[0],
            y=self.position[1],
            z=self.position[2],
            layer_system=layer_system,
            include_direct_field=False)

        power = self.angular_frequency() / 2 * (
            np.conjugate(self.dipole_moment[0]) *
            (e_x_scat + e_x_in) + np.conjugate(self.dipole_moment[1]) *
            (e_y_scat + e_y_in) + np.conjugate(self.dipole_moment[2]) *
            (e_z_scat + e_z_in)).imag
        return self.dissipated_power_homogeneous_background(
            layer_system) + power
kp_vec5 = np.linspace(0, 6, 1000) * k + 1.01 * k
kp = np.concatenate([kp_vec1, kp_vec2, kp_vec3, kp_vec4, kp_vec5])

a = np.linspace(0, 2 * np.pi, num=200)
pwe_ref = [-100, -100, -100]
swe_ref = [-400, 200, 500]
fieldpoint = [-500, 310, 620]
vb = [0, 800]

layer_system = lay.LayerSystem([0, 0], [1, 1])

x = np.array([fieldpoint[0]])
y = np.array([fieldpoint[1]])
z = np.array([fieldpoint[2]])

swe = fldex.SphericalWaveExpansion(k=k, l_max=3, m_max=3, kind='outgoing', reference_point=swe_ref)
swe.coefficients[0] = 2
swe.coefficients[1] = -3j
swe.coefficients[16] = 1
swe.coefficients[18] = 0.5

kp2 = np.linspace(0, 2, num=1000) * k
pwe = fldex.PlaneWaveExpansion(k=k, k_parallel=kp2, azimuthal_angles=a, kind='upgoing', reference_point=pwe_ref,
                               lower_z=vb[0], upper_z=vb[1])
pwe.coefficients[0, :, :] = 100000 * np.exp(- pwe.k_parallel_grid() / k / 20)
pwe.coefficients[1, :, :] = -100000 * np.exp(- pwe.k_parallel_grid() / k / 10)


def test_swe2pwe():
    ex, ey, ez = swe.electric_field(x, y, z)
    pwe_up, pwe_down = fldex.swe_to_pwe_conversion(swe, k_parallel=kp, azimuthal_angles=a, layer_system=layer_system)
Beispiel #6
0
    def solve(self):
        """Compute scattered field coefficients and store them 
        in the particles' spherical wave expansion objects."""
        if len(self.particle_list) > 0:
            if self.solver_type == 'LU':
                sys.stdout.write('Solve (LU decomposition)  : ...')
                if not hasattr(self.master_matrix.linear_operator, 'A'):
                    raise ValueError(
                        'LU factorization only possible '
                        'with the option "store coupling matrix".')
                if not hasattr(self.master_matrix, 'LU_piv'):
                    lu, piv = scipy.linalg.lu_factor(
                        self.master_matrix.linear_operator.A,
                        overwrite_a=False)
                    self.master_matrix.LU_piv = (lu, piv)
                b = scipy.linalg.lu_solve(self.master_matrix.LU_piv,
                                          self.t_matrix.right_hand_side())
                sys.stdout.write(' done\n')
                sys.stdout.flush()
            elif self.solver_type == 'gmres':
                rhs = self.t_matrix.right_hand_side()
                start_time = time.time()

                def status_msg(rk):
                    global iter_num
                    iter_msg = ('Solve (GMRES)             : Iter ' +
                                str(iter_num) + ' | Rel. residual: ' +
                                "{:.2e}".format(np.linalg.norm(rk)) +
                                ' | elapsed: ' +
                                str(int(time.time() - start_time)) + 's')
                    sys.stdout.write('\r' + iter_msg)
                    iter_num += 1

                global iter_num
                iter_num = 0
                b, info = scipy.sparse.linalg.gmres(
                    self.master_matrix.linear_operator,
                    rhs,
                    rhs,
                    tol=self.solver_tolerance,
                    callback=status_msg)


#                sys.stdout.write('\n')
            else:
                raise ValueError(
                    'This solver type is currently not implemented.')

        for iS, particle in enumerate(self.particle_list):
            i_iS = self.layer_system.layer_number(particle.position[2])
            n_iS = self.layer_system.refractive_indices[i_iS]
            k = coord.angular_frequency(
                self.initial_field.vacuum_wavelength) * n_iS
            loz, upz = self.layer_system.lower_zlimit(
                i_iS), self.layer_system.upper_zlimit(i_iS)
            particle.scattered_field = fldex.SphericalWaveExpansion(
                k=k,
                l_max=particle.l_max,
                m_max=particle.m_max,
                kind='outgoing',
                reference_point=particle.position,
                lower_z=loz,
                upper_z=upz)
            particle.scattered_field.coefficients = b[
                self.master_matrix.index_block(iS)]