def RelaunchRays1(self, xp, eikonal, vg, a, L, material):
        '''Use wave data to create a new ray distribution.
		At present azimuthal phase variation is ignored.

		:param numpy.ndarray xp: phase space data with shape (Nb,7,8)
		:param numpy.ndarray eik: eikonal data with shape (Nb,4)
		:param numpy.ndarray vg: group velocity with shape (Nb,7,4)
		:param numpy.ndarray a: vector potential with shape (Nw,Nx,Ny)
		:param float L: length of the wave zone
		:param class material: dispersion object rays are emerging from'''
        # Assume vacuum for now
        wn, xn, yn, ext = self.GetGridInfo()
        a, xn = grid_tools.AddGhostCells(a, xn, 1)
        # Work out the eikonal wavevectors indirectly
        # This is equivalent to k = grad(phase), but does not require unwrapping phase
        eps = np.max(np.abs(a)) * 1e-6
        if xn.shape[0] > 1:
            dx = xn[1] - xn[0]
            adxastar = a * np.gradient(np.conj(a), dx, axis=1)
            kx = np.real(0.5j *
                         (adxastar - np.conj(adxastar))) / (eps + np.abs(a))**2
        else:
            dx = 1.0
            kx = np.zeros(a.shape)
        phase = scipy.integrate.cumtrapz(kx, dx=dx, axis=1, initial=0.0)
        phase -= 0.25 * kx[:, (0, ), :] * dx
        # Rays keep their original frequency and transverse positions.
        # Frequency shifts are still accounted for because amplitude may change.
        rho, phi = self.GetCylCoords(xp)
        impact = np.where(
            np.logical_and(rho[:, 0] < xn[-1], xp[:, 0, 4] < wn[-1]))[0]
        w = xp[impact, :, 4]
        x = rho[impact, :]
        y = phi[impact, :]
        try:
            kr = grid_tools.DataFromGrid(w, x, y, wn, xn, yn, kx)
        except:
            kr = np.zeros(y.shape)
        kr[np.where(kr**2 >= w**2)] = 0.0
        xp[impact, :, 5] = kr * np.cos(y)
        xp[impact, :, 6] = kr * np.sin(y)
        xp[impact, :,
           7] = np.sqrt(w**2 - xp[impact, :, 5]**2 - xp[impact, :, 6]**2)
        vg[impact, ...] = xp[impact, ..., 4:8] / xp[impact, ..., 4:5]
        speed = np.sqrt(vg[impact, :, 1]**2 + vg[impact, :, 2]**2 +
                        vg[impact, :, 3]**2)
        xp[impact, :, 0] += L / speed
        xp[impact, :, 3] += L
        try:
            eikonal[impact,
                    0] = grid_tools.DataFromGrid(w[:, 0], x[:, 0], y[:, 0], wn,
                                                 xn, yn, phase)
            eikonal[impact,
                    1] = grid_tools.DataFromGrid(w[:, 0], x[:, 0], y[:, 0], wn,
                                                 xn, yn, np.abs(a))
        except:
            eikonal[impact, 0] *= 1.0
            eikonal[impact, 1] *= 1.0
        eikonal[impact, 2] = 0.0
        eikonal[impact, 3] = 0.0
    def RelaunchRays(self, xp, eikonal, vg, a, L, material):
        '''Use wave data to create a new ray distribution.

		:param numpy.ndarray xp: phase space data with shape (Nb,7,8)
		:param numpy.ndarray eik: eikonal data with shape (Nb,4)
		:param numpy.ndarray vg: group velocity with shape (Nb,7,4)
		:param numpy.ndarray a: vector potential with shape (Nw,Nx,Ny)
		:param float L: length of the wave zone
		:param class material: dispersion object rays are emerging from'''
        warnings.warn(
            'Using simplified ray relaunch; only valid for close couplings.')
        # Assume vacuum for now
        wn, xn, yn, ext = self.GetGridInfo()
        # Rays keep their original frequency and transverse positions.
        # Frequency shifts are still accounted for because amplitude may change.
        rho, phi = self.GetCylCoords(xp)
        wtest = np.logical_and(xp[:, 0, 4] >= wn[0], xp[:, 0, 4] <= wn[-1])
        impact = np.where(np.logical_and(rho[:, 0] <= xn[-1], wtest))[0]
        w = xp[impact, :, 4]
        x = rho[impact, :]
        y = phi[impact, :]
        xp[impact, :, 5] = 0.0
        xp[impact, :, 6] = 0.0
        xp[impact, :, 7] = w
        vg[impact, ...] = xp[impact, ..., 4:8] / xp[impact, ..., 4:5]
        xp[impact, :, 0] += L / material.GroupVelocityMagnitude(w)
        xp[impact, :, 3] += L
        eikonal[impact,
                0] = w[:, 0] * xp[impact, 0, 0] + grid_tools.DataFromGrid(
                    w[:, 0], x[:, 0], y[:, 0], wn, xn, yn, np.angle(a))
        eikonal[impact, 1] = grid_tools.DataFromGrid(w[:, 0], x[:, 0], y[:, 0],
                                                     wn, xn, yn, np.abs(a))
        eikonal[impact, 2] = 0.0
        eikonal[impact, 3] = 0.0
Exemplo n.º 3
0
 def test_full_slab_edge(self):
     a = np.ones((4, 4, 4))
     a[2, 2, 3] = 2.0
     wn = grid_tools.cyclic_nodes(0.0, 4.0, 4)
     xn = grid_tools.cell_centers(0.0, 4.0, 4)
     yn = grid_tools.cell_centers(0.0, 4.0, 4)
     w = np.array([2.0, 2.0, 2.0])
     x = np.array([2.5, 2.5, 2.5])
     y = np.array([4.0, 3.5, 3.0])
     data = grid_tools.DataFromGrid(w, x, y, wn, xn, yn, a)
     assert np.allclose(data, [2.5, 2.0, 1.5])
Exemplo n.º 4
0
    def RelaunchRays(self, xp, eikonal, vg, a, L):
        '''Use wave data to create a new ray distribution.

		:param numpy.ndarray xp: phase space data with shape (Nb,7,8)
		:param numpy.ndarray eik: eikonal data with shape (Nb,4)
		:param numpy.ndarray vg: group velocity with shape (Nb,7,4)
		:param numpy.ndarray a: vector potential with shape (Nw,Nx,Ny)
		:param float L: length of the wave zone'''
        # Assume vacuum for now
        wn, xn, yn, ext = self.GetGridInfo()
        # Work out the eikonal wavevectors indirectly
        # This is equivalent to k = grad(phase), but does not require unwrapping phase
        eps = np.max(np.abs(a)) * 1e-6
        if xn.shape[0] > 1:
            dx = xn[1] - xn[0]
            adxastar = a * np.gradient(np.conj(a), dx, axis=1)
            kx = np.real(0.5j *
                         (adxastar - np.conj(adxastar))) / (eps + np.abs(a))**2
        else:
            dx = 1.0
            kx = np.zeros(a.shape)
        if yn.shape[0] > 1:
            dy = yn[1] - yn[0]
            adyastar = a * np.gradient(np.conj(a), dy, axis=2)
            ky = np.real(0.5j *
                         (adyastar - np.conj(adyastar))) / (eps + np.abs(a))**2
        else:
            dy = 1.0
            ky = np.zeros(a.shape)
        # Work out the phase using del^2(phase) = div(k)
        # Solve in Fourier space: -K2*phase = iKx*kx + iKy*ky
        iKx = 1j * np.outer(self.T.k_diff(1), np.ones(kx.shape[2]))
        iKy = 1j * np.outer(np.ones(ky.shape[1]), self.T.k_diff(2))
        source = iKx * np.fft.fft(np.fft.fft(
            kx, axis=1), axis=2) + iKy * np.fft.fft(np.fft.fft(ky, axis=1),
                                                    axis=2)
        K2m = iKx**2 + iKy**2
        source[:, 0, 0] = 0.0
        K2m[0, 0] = 1.0
        phase = np.real(np.fft.ifft(np.fft.ifft(source / K2m, axis=2), axis=1))
        # Rays keep their original frequency and transverse positions.
        # Frequency shifts are still accounted for because amplitude may change.
        impact = self.ClipRaysToGrid(xp)
        w = xp[impact, :, 4]
        x = xp[impact, :, 1]
        y = xp[impact, :, 2]
        k1 = grid_tools.DataFromGrid(w, x, y, wn, xn, yn, kx)
        k2 = grid_tools.DataFromGrid(w, x, y, wn, xn, yn, ky)
        sel = np.where(k1**2 + k2**2 >= w**2)
        k1[sel] = 0.0
        k2[sel] = 0.0
        xp[impact, :, 0] += L
        xp[impact, :, 3] += L
        xp[impact, :, 5] = k1
        xp[impact, :, 6] = k2
        xp[impact, :, 7] = np.sqrt(w**2 - k1**2 - k2**2)
        eikonal[impact, 0] = grid_tools.DataFromGrid(w[:, 0], x[:, 0], y[:, 0],
                                                     wn, xn, yn, phase)
        eikonal[impact, 1] = grid_tools.DataFromGrid(w[:, 0], x[:, 0], y[:, 0],
                                                     wn, xn, yn, np.abs(a))
        eikonal[impact, 2] = 0.0
        eikonal[impact, 3] = 0.0
        vg[impact, ...] = xp[impact, ..., 4:8] / xp[impact, ..., 4:5]