Beispiel #1
0
    def init(self, kw):

        # Get the grid
        grid = self.solver.grid
        if not type(grid) == PICMI_CylindricalGrid:
            raise ValueError('When using fbpic with PICMI, '
                             'the grid needs to be a CylindricalGrid object.')
        # Check rmin and boundary conditions
        assert grid.rmin == 0.
        assert grid.bc_zmin == grid.bc_zmax
        assert grid.bc_zmax in ['periodic', 'open']
        assert grid.bc_rmax in ['reflective', 'open']

        # Determine timestep
        if self.solver.cfl is not None:
            dz = (grid.zmax - grid.zmin) / grid.nz
            dt = self.solver.cfl * dz / c
        elif self.time_step_size is not None:
            dt = self.time_step_size
        else:
            raise ValueError('You need to either set the `cfl` of the solver\n'
                             'or the `timestep_size` of the `Simulation`.')

        # Convert API for the smoother
        if self.solver.source_smoother is None:
            smoother = BinomialSmoother()
        else:
            smoother = BinomialSmoother(
                n_passes=self.solver.source_smoother.n_pass,
                compensator=self.solver.source_smoother.compensation)

        # Order of the stencil for z derivatives in the Maxwell solver
        if self.solver.stencil_order is None:
            n_order = -1
        else:
            n_order = self.solver.stencil_order[-1]

        # Initialize and store the FBPIC simulation object
        self.fbpic_sim = FBPICSimulation(Nz=int(grid.nz),
                                         zmin=grid.zmin,
                                         zmax=grid.zmax,
                                         Nr=int(grid.nr),
                                         rmax=grid.rmax,
                                         Nm=grid.n_azimuthal_modes,
                                         dt=dt,
                                         use_cuda=True,
                                         smoother=smoother,
                                         n_order=n_order,
                                         boundaries={
                                             'z': grid.bc_zmax,
                                             'r': grid.bc_rmax
                                         })

        # Set the moving window
        if grid.moving_window_velocity is not None:
            self.fbpic_sim.set_moving_window(grid.moving_window_velocity[-1])
def charge_cylinder(shape, show=False):
    "On-axis cylinder of charge for different radii"
    # Initialize the simulation object
    sim = Simulation( Nz, zmax, Nr, rmax, Nm, (zmax-zmin)/Nz/c,
        p_zmin, p_zmax, p_rmin, p_rmax, p_nz, p_nr, p_nt, n_e,
        zmin=zmin, boundaries={'z':'periodic', 'r':'reflective'}, verbose_level=0,
        smoother=BinomialSmoother(1, False), particle_shape=shape)
    # store results in dict
    res = {}
    # Scale the radius of the cylinder and calculate the space charge field
    for i, scale in enumerate(scales):
        res[scale] = calculate_fields(sim, scale)

    if show is False:
        for i, scale in enumerate(scales):
            r, Er, Er_theory, rho_n = res[scale]
            # Check that the density is correct in mode 0, below this index
            assert np.allclose( (-Er*r)[-5:], (Er_theory*r)[-5:], 1.e-3 )
    else:
        import matplotlib.pyplot as plt
        import matplotlib
        # Segmented colormap
        cmap = matplotlib.cm.get_cmap('YlGnBu')
        colors = np.array([co for co in cmap(np.linspace(0.2,0.8,7))])[::-1]
        # Plot charge density
        plt.title('Cylinder charge density')
        for i, scale in enumerate(scales):
            r, Er, Er_theory, rho_n = res[scale]
            plt.plot(r*1.e6, rho_n/(n_e*e), label=str(scale), color=colors[i])
        plt.legend()
        plt.xlim(0, 1.25)
        plt.ylabel(r'$\rho_n$')
        plt.xlabel(r'$r$')
        plt.show()
        # Plot simulated and analytically calculated field
        plt.title('Cylinder space charge field')
        for i, scale in enumerate(scales):
            r, Er, Er_theory, rho_n = res[scale]
            E0 = (n_e*e*p_rmax**2/(2*epsilon_0))
            plt.plot(r*1.e6, -Er*r/E0, label=str(scale), color=colors[i])
            plt.plot(r*1.e6, Er_theory*r/E0, color=colors[i], ls='--')
        plt.legend()
        plt.xlim(0, 1.25)
        plt.ylabel(r'$-E_{r,norm} \times r$')
        plt.xlabel(r'$r$')
        plt.show()
Beispiel #3
0
    def init(self, kw):

        self.sim_kw = {}
        for argname in ['use_ruyten_shapes', 'use_modified_volume']:
            if f'fbpic_{argname}' in kw:
                self.sim_kw[argname] = kw.pop(f'fbpic_{argname}')

        self.step_kw = {}
        for argname in [
                'correct_currents', 'correct_divE', 'use_true_rho',
                'move_positions', 'move_momenta', 'show_progress'
        ]:
            if f'fbpic_{argname}' in kw:
                self.step_kw[argname] = kw.pop(f'fbpic_{argname}')

        # Get the grid
        grid = self.solver.grid
        if not type(grid) == PICMI_CylindricalGrid:
            raise ValueError('When using fbpic with PICMI, '
                             'the grid needs to be a CylindricalGrid object.')
        # Check rmin and boundary conditions
        assert grid.lower_bound[0] == 0.
        assert grid.lower_boundary_conditions[
            1] == grid.upper_boundary_conditions[1]
        if grid.lower_boundary_conditions[1] == 'reflective':
            warnings.warn(
                "FBPIC does not support reflective boundary condition in z.\n"
                "The z boundary condition was automatically converted to 'open'."
            )
            grid.lower_boundary_conditions[1] = 'open'
            grid.upper_boundary_conditions[1] = 'open'
        assert grid.upper_boundary_conditions[1] in ['periodic', 'open']
        assert grid.upper_boundary_conditions[0] in ['reflective', 'open']

        # Determine timestep
        if self.solver.cfl is not None:
            dz = (grid.upper_bound[1] -
                  grid.lower_bound[1]) / grid.number_of_cells[1]
            dr = (grid.upper_bound[0] -
                  grid.lower_bound[0]) / grid.number_of_cells[0]
            if self.gamma_boost is not None:
                beta = np.sqrt(1. - 1. / self.gamma_boost**2)
                dr = dr / ((1 + beta) * self.gamma_boost)
            dt = self.solver.cfl * min(dz, dr) / c
        elif self.time_step_size is not None:
            dt = self.time_step_size
        else:
            raise ValueError('You need to either set the `cfl` of the solver\n'
                             'or the `timestep_size` of the `Simulation`.')

        # Convert API for the smoother
        if self.solver.source_smoother is None:
            smoother = BinomialSmoother()
        else:
            if self.solver.source_smoother.n_pass is None:
                n_passes = 1
            else:
                n_passes = {
                    'r': self.solver.source_smoother.n_pass[0],
                    'z': self.solver.source_smoother.n_pass[1]
                }
            if self.solver.source_smoother.compensation is None:
                compensator = False
            else:
                compensator = all(self.solver.source_smoother.compensation)
            smoother = BinomialSmoother(n_passes=n_passes,
                                        compensator=compensator)

        # Convert verbose level:
        verbose_level = self.verbose
        if verbose_level is None:
            verbose_level = 1

        # Order of the stencil for z derivatives in the Maxwell solver
        if self.solver.stencil_order is None:
            n_order = -1
        else:
            n_order = self.solver.stencil_order[-1]

        # Number of guard cells
        if grid.guard_cells is None:
            n_guard = None
        else:
            n_guard = grid.guard_cells[-1]

        if self.solver.galilean_velocity is None:
            v_comoving = None
        else:
            v_comoving = self.solver.galilean_velocity[-1]

        # Initialize and store the FBPIC simulation object
        self.fbpic_sim = FBPICSimulation(Nz=int(grid.number_of_cells[1]),
                                         zmin=grid.lower_bound[1],
                                         zmax=grid.upper_bound[1],
                                         Nr=int(grid.number_of_cells[0]),
                                         rmax=grid.upper_bound[0],
                                         Nm=grid.n_azimuthal_modes,
                                         dt=dt,
                                         use_cuda=True,
                                         smoother=smoother,
                                         n_order=n_order,
                                         boundaries={
                                             'z':
                                             grid.upper_boundary_conditions[1],
                                             'r':
                                             grid.upper_boundary_conditions[0]
                                         },
                                         n_guard=n_guard,
                                         verbose_level=verbose_level,
                                         particle_shape=self.particle_shape,
                                         v_comoving=v_comoving,
                                         gamma_boost=self.gamma_boost,
                                         **self.sim_kw)

        # Set the moving window
        if grid.moving_window_velocity is not None:
            self.fbpic_sim.set_moving_window(grid.moving_window_velocity[-1])