# Create ground plate
plate = ZPlane(voltage=extractor_voltage, zcent=zplate)
installconductor(plate, dfill=largepos)

# Setup the particle scraper
scraper = ParticleScraper([source, plate])

# ## Define diagnostics

particleperiod = 100
particle_diagnostic_0 = ParticleDiagnostic(
    period=particleperiod,
    top=top,
    w3d=w3d,
    species={species.name: species
             for species in listofallspecies},
    comm_world=comm_world,
    lparallel_output=False,
    write_dir=diagDir[:-5])
fieldperiod = 100
efield_diagnostic_0 = FieldDiagnostic.ElectrostaticFields(
    solver=solverE,
    top=top,
    w3d=w3d,
    comm_world=comm_world,
    period=fieldperiod)

installafterstep(particle_diagnostic_0.write)
installafterstep(efield_diagnostic_0.write)
Пример #2
0
      ptitles('n','z [um]','X [um]')
      em.pfez(view=5,titles=0,xscale=1e6,yscale=1.e6,gridscale=1.e-9,l_transpose=1,direction=1)
      ptitles('Ez [GV/m]','z [um]','X [um]')
      #ions_C.ppzx(view=6)
      #elec_C.ppzx(color=red,view=6)
      #ions_H.ppzx(color=blue,view=6)
      #elec_H.ppzx(color=cyan,view=6)

installafterstep(liveplots)


# Load additional OpenPMD diagnostic
diag_f = FieldDiagnostic( period=fielddiag_period, top=top, w3d=w3d, em=em,
                          comm_world=comm_world, lparallel_output=l_parallelo )
diag_elec_C = ParticleDiagnostic( period=partdiag_period, top=top, w3d=w3d,
            species = {"elec_C" : elec_C},
            comm_world=comm_world, lparallel_output=l_parallelo )
diag_elec_H = ParticleDiagnostic( period=partdiag_period, top=top, w3d=w3d,
            species = {"elec_H" : elec_H},
            comm_world=comm_world, lparallel_output=l_parallelo )
diag_ions_C = ParticleDiagnostic( period=partdiag_period, top=top, w3d=w3d,
            species = {"ions_C" : ions_C},
            comm_world=comm_world, lparallel_output=l_parallelo )
diag_ions_H = ParticleDiagnostic( period=partdiag_period, top=top, w3d=w3d,
            species = {"ions_H" : ions_H},
            comm_world=comm_world, lparallel_output=l_parallelo )

installafterstep( diag_f.write )
installafterstep( diag_elec_C.write )
installafterstep( diag_elec_H.write )
installafterstep( diag_ions_C.write )
Пример #3
0
def main(injection_type,
         cathode_temperature,
         cathode_workfunction,
         anode_workfunction,
         anode_voltage,
         gate_voltage,
         lambdaR,
         beta,
         srefprob,
         drefprob,
         reflection_scheme,
         gap_voltage,
         dgap,
         dt,
         nsteps,
         particles_per_step,
         file_path,
         fieldperiod=100,
         particleperiod=1000,
         reflections=True):
    settings = deepcopy(locals())
    ############################
    # Domain / Geometry / Mesh #
    ############################

    # Grid geometry

    w = 1.6e-3  # full hexagon width
    a = w / 2.0  # inner wall width
    b = 80e-6  # thickness
    r = np.sqrt(3) / 2. * w  # distance between two opposite walls
    d = np.sqrt(b**2 / 4. + b**2)  #
    h = 0.2e-3  # height of grid (length in z)

    PLATE_SPACING = dgap
    CHANNEL_WIDTH_X = w + 2 * d + a
    CHANNEL_WIDTH_Y = 2 * r + 2 * b

    # Dimensions
    X_MAX = +CHANNEL_WIDTH_X / 2.
    X_MIN = -X_MAX
    Y_MAX = +CHANNEL_WIDTH_Y / 2.
    Y_MIN = -Y_MAX
    Z_MAX = PLATE_SPACING
    Z_MIN = 0.

    # Grid parameters
    NUM_X = 100
    NUM_Y = 100
    NUM_Z = 25

    # z step size
    dx = (X_MAX - X_MIN) / NUM_X
    dy = (Y_MAX - Y_MIN) / NUM_Y
    dz = (Z_MAX - Z_MIN) / NUM_Z

    print(" --- (xmin, ymin, zmin) = ({}, {}, {})".format(X_MIN, Y_MIN, Z_MIN))
    print(" --- (xmax, ymax, zmax) = ({}, {}, {})".format(X_MAX, Y_MAX, Z_MAX))
    print(" --- (dx, dy, dz) = ({}, {}, {})".format(dx, dy, dz))

    # Solver Geometry and Boundaries

    # Specify solver geometry
    w3d.solvergeom = w3d.XYZgeom

    # Set field boundary conditions
    w3d.bound0 = dirichlet
    w3d.boundnz = dirichlet
    w3d.boundxy = periodic

    # Particles boundary conditions
    top.pbound0 = absorb
    top.pboundnz = absorb
    top.pboundxy = periodic

    # Set mesh boundaries
    w3d.xmmin = X_MIN
    w3d.xmmax = X_MAX
    w3d.ymmin = Y_MIN
    w3d.ymmax = Y_MAX
    w3d.zmmin = Z_MIN
    w3d.zmmax = Z_MAX

    # Set mesh cell counts
    w3d.nx = NUM_X
    w3d.ny = NUM_Y
    w3d.nz = NUM_Z

    ################
    # FIELD SOLVER #
    ################
    magnetic_field = True
    if magnetic_field:
        bz = np.zeros([w3d.nx, w3d.ny, w3d.nz])
        bz[:, :, :] = 200e-3
        z_start = w3d.zmmin
        z_stop = w3d.zmmax
        top.ibpush = 2
        addnewbgrd(z_start,
                   z_stop,
                   xs=w3d.xmmin,
                   dx=(w3d.xmmax - w3d.xmmin),
                   ys=w3d.ymmin,
                   dy=(w3d.ymmax - w3d.ymmin),
                   nx=w3d.nx,
                   ny=w3d.ny,
                   nz=w3d.nz,
                   bz=bz)

    # Set up fieldsolver
    f3d.mgtol = 1e-6
    solverE = MultiGrid3D()
    registersolver(solverE)

    ###############################
    # PARTICLE INJECTION SETTINGS #
    ###############################
    volts_on_conductor = gap_voltage

    # INJECTION SPECIFICATION
    USER_INJECT = injection_type

    # Cathode and anode settings
    CATHODE_TEMP = cathode_temperature
    CATHODE_PHI = cathode_workfunction
    ANODE_WF = anode_workfunction  # Can be used if vacuum level is being set
    CONDUCTOR_VOLTS = volts_on_conductor  # ACCEL_VOLTS used for velocity and CL calculations

    # Emitted species
    background_beam = Species(type=Electron, name='background')
    # Reflected species
    reflected_electrons = Species(type=Electron, name='reflected')

    # Emitter area and position
    SOURCE_RADIUS_1 = 0.5 * CHANNEL_WIDTH_X  # a0 parameter - X plane
    SOURCE_RADIUS_2 = 0.5 * CHANNEL_WIDTH_Y  # b0 parameter - Y plane
    Z_PART_MIN = dz / 1000.  # starting particle z value

    # Compute cathode area for geomtry-specific current calculations
    if (w3d.solvergeom == w3d.XYZgeom):
        # For 3D cartesion geometry only
        cathode_area = 4. * SOURCE_RADIUS_1 * SOURCE_RADIUS_2
    else:
        # Assume 2D XZ geometry
        cathode_area = 2. * SOURCE_RADIUS_1 * 1.

    # If using the XZ geometry, set so injection uses the same geometry
    top.linj_rectangle = (w3d.solvergeom == w3d.XZgeom
                          or w3d.solvergeom == w3d.XYZgeom)

    # Returns velocity beam_beta (in units of beta) for which frac of emitted particles have v < beam_beta * c
    beam_beta = sources.compute_cutoff_beta(CATHODE_TEMP, frac=0.99)

    PTCL_PER_STEP = particles_per_step
    if USER_INJECT == 1:
        CURRENT_MODIFIER = 0.5  # Factor to multiply CL current by when setting beam current
        # Constant current density - beam transverse velocity fixed to zero, very small longitduinal velocity

        # Set injection flag
        top.inject = 1  # 1 means constant; 2 means space-charge limited injection;# 6 means user-specified
        top.npinject = PTCL_PER_STEP
        beam_current = 4. / 9. * eps0 * sqrt(2. * echarge / background_beam.mass) \
                           * CONDUCTOR_VOLTS ** 1.5 / PLATE_SPACING ** 2 * cathode_area

        background_beam.ibeam = beam_current * CURRENT_MODIFIER

        background_beam.a0 = SOURCE_RADIUS_1
        background_beam.b0 = SOURCE_RADIUS_2
        background_beam.ap0 = .0e0
        background_beam.bp0 = .0e0

        w3d.l_inj_exact = True

        # Initial velocity settings (5% of c)
        vrms = np.sqrt(1 - 1 / (0.05 / 511e3 + 1)**2) * 3e8
        top.vzinject = vrms

    if USER_INJECT == 2:
        # SC limited Thermionic injection
        top.inject = 2

        # Set both beams to same npinject to keep weights the same
        background_beam.npinject = PTCL_PER_STEP
        top.finject = [1.0, 0.0]
        w3d.l_inj_exact = True

        # Specify thermal properties
        background_beam.vthz = np.sqrt(CATHODE_TEMP * kb_J /
                                       background_beam.mass)
        background_beam.vthperp = np.sqrt(CATHODE_TEMP * kb_J /
                                          background_beam.mass)
        top.lhalfmaxwellinject = 1  # inject z velocities as half Maxwellian

        beam_current = sources.j_rd(
            CATHODE_TEMP,
            CATHODE_PHI) * cathode_area  # steady state current in Amps
        print('beam current expected: {}, current density {}'.format(
            beam_current, beam_current / cathode_area))
        jcl = 0.
        if gap_voltage > 0.:
            jcl = 4. / 9. * eps0 * sqrt(2. * echarge / background_beam.mass) \
                * CONDUCTOR_VOLTS ** 1.5 / PLATE_SPACING ** 2 * cathode_area
        print('child-langmuir  limit: {}, current density {}'.format(
            jcl, jcl / cathode_area))
        background_beam.ibeam = beam_current
        background_beam.a0 = SOURCE_RADIUS_1
        background_beam.b0 = SOURCE_RADIUS_2
        background_beam.ap0 = .0e0
        background_beam.bp0 = .0e0

    if USER_INJECT == 4:
        w3d.l_inj_exact = True
        w3d.l_inj_user_particles_v = True

        # Schottky model
        top.inject = 1
        top.ninject = 1
        top.lhalfmaxwellinject = 1  # inject z velocities as half Maxwellian
        top.zinject = np.asarray([Z_PART_MIN])
        top.ainject = np.asarray([SOURCE_RADIUS_1])
        top.binject = np.asarray([SOURCE_RADIUS_2])
        top.finject = np.asarray([[1.0, 0.0]])

        electric_field = 0
        delta_w = np.sqrt(e**3 * electric_field / (4 * np.pi * eps0))
        A0 = 1.20173e6
        AR = A0 * lambdaR

        background_beam.a0 = SOURCE_RADIUS_1
        background_beam.b0 = SOURCE_RADIUS_2
        background_beam.ap0 = .0e0
        background_beam.bp0 = .0e0
        background_beam.vthz = np.sqrt(CATHODE_TEMP * kb_J /
                                       background_beam.mass)
        background_beam.vthperp = np.sqrt(CATHODE_TEMP * kb_J /
                                          background_beam.mass)

        # use Richardson current to estimate particle weight
        rd_current = AR * CATHODE_TEMP**2 * np.exp(
            -(CATHODE_PHI * e) / (CATHODE_TEMP * k)) * cathode_area
        electrons_per_second = rd_current / e
        electrons_per_step = electrons_per_second * dt
        background_beam.sw = electrons_per_step / PTCL_PER_STEP

        def schottky_emission():
            # schottky emission at cathode side

            global num_particles_res

            Ez = solverE.getez()
            Ez_mean = np.mean(Ez[:, :, 0])

            if w3d.inj_js == background_beam.js:
                delta_w = 0.
                if Ez_mean < 0.:
                    delta_w = np.sqrt(beta * e**3 * np.abs(Ez_mean) /
                                      (4 * np.pi * eps0))

                rd_current = AR * CATHODE_TEMP**2 * np.exp(
                    -(CATHODE_PHI * e - delta_w) /
                    (CATHODE_TEMP * k)) * cathode_area
                electrons_per_second = rd_current / e
                electrons_per_step = electrons_per_second * top.dt
                float_num_particles = electrons_per_step / background_beam.sw
                num_particles = int(float_num_particles + num_particles_res +
                                    np.random.rand())
                num_particles_res += float_num_particles - num_particles

                # --- inject np particles of species electrons1
                # --- Create the particles on the surface
                x = -background_beam.a0 + 2 * background_beam.a0 * np.random.rand(
                    num_particles)
                y = -background_beam.b0 + 2 * background_beam.b0 * np.random.rand(
                    num_particles)
                vz = np.random.rand(num_particles)
                vz = np.maximum(1e-14 * np.ones_like(vz), vz)
                vz = background_beam.vthz * np.sqrt(-2.0 * np.log(vz))

                vrf = np.random.rand(num_particles)
                vrf = np.maximum(1e-14 * np.ones_like(vrf), vrf)
                vrf = background_beam.vthz * np.sqrt(-2.0 * np.log(vrf))
                trf = 2 * np.pi * np.random.rand(num_particles)
                vx = vrf * np.cos(trf)
                vy = vrf * np.sin(trf)

                # --- Setup the injection arrays
                w3d.npgrp = num_particles
                gchange('Setpwork3d')
                # --- Fill in the data. All have the same z-velocity, vz1.
                w3d.xt[:] = x
                w3d.yt[:] = y
                w3d.uxt[:] = vx
                w3d.uyt[:] = vy
                w3d.uzt[:] = vz

        installuserparticlesinjection(schottky_emission)

    derivqty()

    print("weight:", background_beam.sw)

    ##########################
    # CONDUCTOR INSTALLATION #
    ##########################
    install_conductor = True

    # --- Anode Location
    zplate = Z_MAX

    # Create source conductors
    if install_conductor:
        emitter = ZPlane(zcent=w3d.zmmin, zsign=-1., voltage=0., condid=2)
    else:
        emitter = ZPlane(zcent=w3d.zmmin, zsign=-1., voltage=0.)

    # Create collector
    if install_conductor:
        collector = ZPlane(voltage=gap_voltage, zcent=zplate, condid=3)
    else:
        collector = ZPlane(voltage=gap_voltage, zcent=zplate)

    # Create grid

    if install_conductor:
        # Offsets to make sure grid is centered after install
        # Because case089 was not made with a hexagon at (0., 0.) it must be moved depending on STL file used and
        # version of STLconductor
        cxmin, cymin, czmin = -0.00260785012506, -0.00312974047847, 0.000135000009323
        cxmax, cymax, czmax = 0.00339215015993, 0.00287025980651, 0.000335000018822
        conductor = STLconductor(
            "honeycomb_case0.89t_xycenter_zcen470.stl",
            xcent=cxmin + (cxmax - cxmin) / 2.,
            ycent=cymin + (cymax - cymin) /
            2.,  #zcent=czmin + (czmax - czmin) / 2., disp=(0.,0.,1e-6),
            verbose="on",
            voltage=gate_voltage,
            normalization_factor=dz,
            condid=1)

    if install_conductor:
        installconductor(conductor, dfill=largepos)
        installconductor(emitter, dfill=largepos)
        installconductor(collector, dfill=largepos)
        scraper_diode = ParticleScraper([emitter, collector],
                                        lcollectlpdata=True,
                                        lsaveintercept=True)
        scraper_gate = ParticleScraper([conductor],
                                       lcollectlpdata=True,
                                       lsaveintercept=False)

        scraper_dictionary = {1: 'grid', 2: 'emitter', 3: 'collector'}
    else:
        installconductor(emitter, dfill=largepos)
        installconductor(collector, dfill=largepos)
        scraper = ParticleScraper([emitter, collector],
                                  lcollectlpdata=True,
                                  lsaveintercept=True)
        scraper_dictionary = {1: 'emitter', 2: 'collector'}

    ########################
    # Hacked Grid Scraping #
    ########################
    # Implements boxes with a reflection probability based on transparency attribute
    # used to crudely emulate particles reflected from the STLconductor honeycomb which cannot provide
    # scraper positions needed for reflection calculation
    grid_reflections = True

    if grid_reflections:
        grid_front = Box(xcent=0.,
                         ycent=0.,
                         zcent=0.135e-3 - dz / 2.,
                         xsize=2 * (X_MAX - X_MIN),
                         ysize=2 * (Y_MAX - Y_MIN),
                         zsize=dz)
        grid_back = Box(xcent=0.,
                        ycent=0.,
                        zcent=0.335e-3 + dz / 2,
                        xsize=2 * (X_MAX - X_MIN),
                        ysize=2 * (Y_MAX - Y_MIN),
                        zsize=dz)

        scraper_front = ParticleScraperGrid(grid_front,
                                            lcollectlpdata=True,
                                            lsaveintercept=True)
        scraper_back = ParticleScraperGrid(grid_back,
                                           lcollectlpdata=True,
                                           lsaveintercept=True)

        # Fraction of particles expected to pass through the conductor (assuming they cross it in a single step)
        scraper_front.transparency = 0.80
        scraper_back.transparency = 0.80

        # Directional scraper to prevent particles from being scraped coming out of honeycomb interior
        scraper_front.directional_scraper = -1
        scraper_back.directional_scraper = +1

    #####################
    # Diagnostics Setup #
    #####################

    efield_diagnostic_0 = FieldDiagnostic.ElectrostaticFields(
        solver=solverE,
        top=top,
        w3d=w3d,
        comm_world=comm_world,
        period=fieldperiod,
        write_dir=os.path.join(file_path, 'fields'))
    installafterstep(efield_diagnostic_0.write)

    particle_diagnostic_0 = ParticleDiagnostic(
        period=particleperiod,
        top=top,
        w3d=w3d,
        species={species.name: species
                 for species in listofallspecies},
        comm_world=comm_world,
        lparallel_output=False,
        write_dir=file_path)
    installafterstep(particle_diagnostic_0.write)

    ####################
    # CONTROL SEQUENCE #
    ####################

    # prevent gist from starting upon setup
    top.lprntpara = false
    top.lpsplots = false

    top.verbosity = 1  # Reduce solver verbosity
    solverE.mgverbose = 1  # further reduce output upon stepping - prevents websocket timeouts in Jupyter notebook

    init_iters = 2000
    regular_iters = 50

    init_tol = 1e-5
    regular_tol = 1e-6

    # Time Step
    top.dt = dt

    # Define and install particle reflector
    if reflections:
        collector_reflector = ParticleReflector(scraper=scraper_diode,
                                                conductor=collector,
                                                spref=reflected_electrons,
                                                srefprob=srefprob,
                                                drefprob=drefprob,
                                                refscheme=reflection_scheme)
        installparticlereflector(collector_reflector)
        print("reflection_scheme = " + reflection_scheme)
    else:
        print("reflections: off")

    if grid_reflections:
        reflector_front = ParticleReflector(scraper=scraper_front,
                                            conductor=grid_front,
                                            spref=reflected_electrons,
                                            srefprob=srefprob,
                                            drefprob=0.75,
                                            refscheme=reflection_scheme)
        installparticlereflector(reflector_front)

        reflector_back = ParticleReflector(scraper=scraper_back,
                                           conductor=grid_back,
                                           spref=reflected_electrons,
                                           srefprob=srefprob,
                                           drefprob=0.75,
                                           refscheme=reflection_scheme)
        installparticlereflector(reflector_back)

    # initialize field solver and potential field
    solverE.mgmaxiters = init_iters
    solverE.mgtol = init_tol

    package("w3d")
    generate()

    # Specify particle weight for reflected_electrons
    reflected_electrons.sw = background_beam.sw
    print("weight: background_beam = {}, reflected = {}".format(
        background_beam.sw, reflected_electrons.sw))

    solverE.mgmaxiters = regular_iters
    solverE.mgtol = regular_tol
    step(nsteps)

    ####################
    # Final Output     #
    ####################

    surface_charge = analyze_collected_charge(top, solverE)
    if reflections:
        reflected_charge = analyze_reflected_charge(top, [collector_reflector],
                                                    comm_world=comm_world)

    if comm_world.rank == 0:
        filename = os.path.join(
            file_path, "all_charge_anodeV_{}.h5".format(anode_voltage))
        diag_file = h5.File(filename, 'w')

        # Write simulation parameters
        for key, val in settings.items():
            diag_file.attrs[key] = val
        for dom_attr in [
                'xmmin', 'xmmax', 'ymmin', 'ymmax', 'zmmin', 'zmmax', 'nx',
                'ny', 'nz'
        ]:
            diag_file.attrs[dom_attr] = eval('w3d.' + dom_attr)

        # Record scraped particles into scraper group of file
        scraper_data = diag_file.create_group('scraper')
        for key, val in scraper_dictionary.items():
            scraper_data.attrs[val] = key

        for condid, cond_data in surface_charge.items():
            cond_group = scraper_data.create_group('{}'.format(
                scraper_dictionary[condid]))
            for i, spec_dat in enumerate(cond_data):
                cond_group.create_dataset(listofallspecies[i].name,
                                          data=spec_dat)

        # Record reflected particles into reflector group
        if reflections:
            reflector_data = diag_file.create_group('reflector')
            for key in reflected_charge:
                reflector_data.attrs[scraper_dictionary[key]] = key

            for condid, ref_data in reflected_charge.items():
                refl_group = reflector_data.create_group('{}'.format(
                    scraper_dictionary[condid]))
                refl_group.create_dataset('reflected', data=ref_data)

        diag_file.close()
Пример #4
0
def main(x_struts,
         y_struts,
         V_grid,
         grid_height,
         strut_width,
         strut_height,
         rho_ew,
         T_em,
         phi_em,
         T_coll,
         phi_coll,
         rho_cw,
         gap_distance,
         rho_load,
         run_id,
         channel_width=100e-9,
         injection_type=2,
         magnetic_field=0.0,
         random_seed=True,
         install_grid=True,
         install_circuit=True,
         max_wall_time=1e9,
         particle_diagnostic_switch=False,
         field_diagnostic_switch=False,
         lost_diagnostic_switch=False):
    """
    Run a simulation of a gridded TEC.
    Args:
        x_struts: Number of struts that intercept the x-axis.
        y_struts: Number of struts that intercept the y-axis
        V_grid: Voltage to place on the grid in Volts.
        grid_height: Distance from the emitter to the grid normalized by gap_distance, unitless.
        strut_width: Transverse extent of the struts in meters.
        strut_height: Longitudinal extent of the struts in meters.
        rho_ew: Emitter side wiring resistivity, ohms*cm.
        T_em: Emitter temperature, kelvin.
        phi_em: Emitter work function, eV.
        T_coll: Collector termperature, kelvin.
        phi_coll: Collector work function, eV.
        rho_cw: Collector side wiring resistivity, ohms*cm.
        gap_distance: Distance from emitter to collector, meters.
        rho_load: Load resistivity, ohms*cm.
        run_id: Run ID. Mainly used for parallel optimization.
        injection_type: 1: For constant current emission with only thermal velocity spread in z and CL limited emission.
                        2: For true thermionic emission. Velocity spread along all axes.
        random_seed: True/False. If True, will force a random seed to be used for emission positions.
        install_grid: True/False. If False the grid will not be installed. Results in simple parallel plate setup.
                                  If False then phi_em - phi_coll specifies the voltage on the collector.
        install_circuit: True/False. Include external circuit that will modulate gap voltage based on
                                     current flow and contact potential between cathode/anode.
        max_wall_time: Wall time to allow simulation to run for. Simulation is periodically checked and will halt if it
                        appears the next segment of the simulation will exceed max_wall_time. This is not guaranteed to
                        work since the guess is based on the run time up to that point.
                        Intended to be used when running on system with job manager.
        particle_diagnostic_switch: True/False. Use openPMD compliant .h5 particle diagnostics.
        field_diagnostic_switch: True/False. Use rswarp electrostatic .h5 field diagnostics (Maybe openPMD compliant?).
        lost_diagnostic_switch: True/False. Enable collection of lost particle coordinates
                        with rswarp.diagnostics.parallel.save_lost_particles.

    """
    # record inputs and set parameters
    run_attributes = deepcopy(locals())

    for key in run_attributes:
        if key in efficiency.tec_parameters:
            efficiency.tec_parameters[key][0] = run_attributes[key]

    # set new random seed
    if random_seed:
        top.seedranf(randint(1, 1e9))

    # Control for printing in parallel
    if comm_world.size != 1:
        synchronizeQueuedOutput_mpi4py(out=True, error=True)

    if particle_diagnostic_switch or field_diagnostic_switch:
        # Directory paths
        diagDir = 'diags_id{}/hdf5/'.format(run_id)
        field_base_path = 'diags_id{}/fields/'.format(run_id)
        diagFDir = {
            'magnetic': 'diags_id{}/fields/magnetic'.format(run_id),
            'electric': 'diags_id{}/fields/electric'.format(run_id)
        }

        # Cleanup command if directories already exist
        if comm_world.rank == 0:
            cleanupPrevious(diagDir, diagFDir)

    load_balance = LoadBalancer()
    ######################
    # DOMAIN/GEOMETRY/MESH
    ######################

    # Dimensions
    X_MAX = +channel_width / 2.
    X_MIN = -X_MAX
    Y_MAX = +channel_width / 2.
    Y_MIN = -Y_MAX
    Z_MAX = gap_distance
    Z_MIN = 0.

    # TODO: cells in all dimensions reduced by 10x for testing, will need to verify if this is reasonable (TEMP)
    # Grid parameters
    dx_want = 5e-9
    dy_want = 5e-9
    dz_want = 5e-9

    NUM_X = int(round(channel_width / dx_want))  # 20 #128 #10
    NUM_Y = int(round(channel_width / dy_want))  # 20 #128 #10
    NUM_Z = int(round(gap_distance / dz_want))

    # mesh spacing
    dz = (Z_MAX - Z_MIN) / NUM_Z
    dx = channel_width / NUM_X
    dy = channel_width / NUM_Y

    print "Channel width: {}, DX = {}".format(channel_width, dx)
    print "Channel width: {}, DY = {}".format(channel_width, dy)
    print "Channel length: {}, DZ = {}".format(gap_distance, dz)

    # Solver Geometry and Boundaries

    # Specify solver geometry
    w3d.solvergeom = w3d.XYZgeom

    # Set field boundary conditions
    w3d.bound0 = neumann
    w3d.boundnz = dirichlet
    w3d.boundxy = periodic
    # Particles boundary conditions
    top.pbound0 = absorb
    top.pboundnz = absorb
    top.pboundxy = periodic

    # Set mesh boundaries
    w3d.xmmin = X_MIN
    w3d.xmmax = X_MAX
    w3d.ymmin = Y_MIN
    w3d.ymmax = Y_MAX
    w3d.zmmin = 0.
    w3d.zmmax = Z_MAX

    # Set mesh cell counts
    w3d.nx = NUM_X
    w3d.ny = NUM_Y
    w3d.nz = NUM_Z

    #############################
    # PARTICLE INJECTION SETTINGS
    #############################

    # Cathode and anode settings
    EMITTER_TEMP = T_em
    EMITTER_PHI = phi_em  # work function in eV
    COLLECTOR_PHI = phi_coll  # Can be used if vacuum level is being set
    ACCEL_VOLTS = V_grid  # ACCEL_VOLTS used for velocity and CL calculations
    collector_voltage = phi_em - phi_coll

    # Emitted species
    background_beam = Species(type=Electron, name='background')
    measurement_beam = Species(type=Electron, name='measurement')

    # Emitter area and position
    SOURCE_RADIUS_1 = 0.5 * channel_width  # a0 parameter - X plane
    SOURCE_RADIUS_2 = 0.5 * channel_width  # b0 parameter - Y plane
    Z_PART_MIN = dz / 1000.  # starting particle z value

    # Compute cathode area for geomtry-specific current calculations
    if (w3d.solvergeom == w3d.XYZgeom):
        # For 3D cartesion geometry only
        cathode_area = 4. * SOURCE_RADIUS_1 * SOURCE_RADIUS_2
    else:
        # Assume 2D XZ geometry
        cathode_area = 2. * SOURCE_RADIUS_1 * 1.

    # If using the XZ geometry, set so injection uses the same geometry
    top.linj_rectangle = (w3d.solvergeom == w3d.XZgeom
                          or w3d.solvergeom == w3d.XYZgeom)

    # Returns velocity beam_beta (in units of beta) for which frac of emitted particles have v < beam_beta * c
    beam_beta = sources.compute_cutoff_beta(EMITTER_TEMP, frac=0.99)

    PTCL_PER_STEP = 100

    if injection_type == 1:
        CURRENT_MODIFIER = 0.5  # Factor to multiply CL current by when setting beam current
        # Constant current density - beam transverse velocity fixed to zero, very small longitduinal velocity

        # Set injection flag
        top.inject = 1  # 1 means constant; 2 means space-charge limited injection;# 6 means user-specified
        top.npinject = PTCL_PER_STEP
        beam_current = 4. / 9. * eps0 * sqrt(2. * echarge / background_beam.mass) \
                       * ACCEL_VOLTS ** 1.5 / gap_distance ** 2 * cathode_area

        background_beam.ibeam = beam_current * CURRENT_MODIFIER

        background_beam.a0 = SOURCE_RADIUS_1
        background_beam.b0 = SOURCE_RADIUS_2
        background_beam.ap0 = .0e0
        background_beam.bp0 = .0e0

        w3d.l_inj_exact = True

        # Initial velocity settings (5% of c)
        vrms = np.sqrt(1 - 1 / (0.05 / 511e3 + 1)**2) * 3e8
        top.vzinject = vrms

    if injection_type == 2:
        # True Thermionic injection
        top.inject = 1

        # Set both beams to same npinject to keep weights the same
        background_beam.npinject = PTCL_PER_STEP
        measurement_beam.npinject = PTCL_PER_STEP

        w3d.l_inj_exact = True

        # Specify thermal properties
        background_beam.vthz = measurement_beam.vthz = np.sqrt(
            EMITTER_TEMP * kb_J / background_beam.mass)
        background_beam.vthperp = measurement_beam.vthperp = np.sqrt(
            EMITTER_TEMP * kb_J / background_beam.mass)
        top.lhalfmaxwellinject = 1  # inject z velocities as half Maxwellian

        beam_current = sources.j_rd(
            EMITTER_TEMP,
            EMITTER_PHI) * cathode_area  # steady state current in Amps
        print('beam current expected: {}, current density {}'.format(
            beam_current, beam_current / cathode_area))
        jcl = 4. / 9. * eps0 * sqrt(2. * echarge / background_beam.mass) \
                       * ACCEL_VOLTS ** 1.5 / gap_distance ** 2 * cathode_area
        print('child-langmuir  limit: {}, current density {}'.format(
            jcl, jcl / cathode_area))
        background_beam.ibeam = measurement_beam.ibeam = beam_current
        background_beam.a0 = measurement_beam.a0 = SOURCE_RADIUS_1
        background_beam.b0 = measurement_beam.b0 = SOURCE_RADIUS_2
        background_beam.ap0 = measurement_beam.ap0 = .0e0
        background_beam.bp0 = measurement_beam.bp0 = .0e0

    derivqty()

    ##############
    # FIELD SOLVER
    ##############
    # Add Uniform B_z field if turned on
    if magnetic_field:
        bz = np.zeros([w3d.nx, w3d.ny, w3d.nz])
        bz[:, :, :] = magnetic_field
        z_start = w3d.zmmin
        z_stop = w3d.zmmax
        top.ibpush = 2
        addnewbgrd(z_start,
                   z_stop,
                   xs=w3d.xmmin,
                   dx=(w3d.xmmax - w3d.xmmin),
                   ys=w3d.ymmin,
                   dy=(w3d.ymmax - w3d.ymmin),
                   nx=w3d.nx,
                   ny=w3d.ny,
                   nz=w3d.nz,
                   bz=bz)

    # Set up fieldsolver
    f3d.mgtol = 1e-6
    solverE = MultiGrid3D()
    registersolver(solverE)

    ########################
    # CONDUCTOR INSTALLATION
    ########################

    if install_grid:
        accel_grid, gl = create_grid(x_struts, y_struts, V_grid,
                                     grid_height * gap_distance, strut_width,
                                     strut_height, channel_width)
        accel_grid.voltage = V_grid

    # --- Anode Location
    zplate = Z_MAX

    # Create source conductors
    if install_grid:
        source = ZPlane(zcent=w3d.zmmin, zsign=-1., voltage=0., condid=2)
    else:
        source = ZPlane(zcent=w3d.zmmin, zsign=-1., voltage=0.)

    # Create ground plate
    total_rho = efficiency.tec_parameters['rho_load'][0]
    if install_grid:
        plate = ZPlane(zcent=zplate, condid=3)
        if install_circuit:
            circuit = ExternalCircuit(top,
                                      solverE,
                                      total_rho,
                                      collector_voltage,
                                      cathode_area * 1e4,
                                      plate,
                                      debug=False)
        plate.voltage = circuit
        # plate.voltage = collector_voltage
    else:
        plate = ZPlane(zcent=zplate)
        if install_circuit:
            circuit = ExternalCircuit(top,
                                      solverE,
                                      total_rho,
                                      collector_voltage,
                                      cathode_area * 1e4,
                                      plate,
                                      debug=False)
        plate.voltage = circuit
        # plate.voltage = collector_voltage

    if install_grid:
        installconductor(accel_grid)
        installconductor(source, dfill=largepos)
        installconductor(plate, dfill=largepos)
        scraper = ParticleScraper([accel_grid, source, plate],
                                  lcollectlpdata=True,
                                  lsaveintercept=True)
        scraper_dictionary = {'grid': 1, 'source': 2, 'collector': 3}
    else:
        installconductor(source, dfill=largepos)
        installconductor(plate, dfill=largepos)
        scraper = ParticleScraper([source, plate],
                                  lcollectlpdata=True,
                                  lsaveintercept=True)
        scraper_dictionary = {'source': 1, 'collector': 2}

    #############
    # DIAGNOSTICS
    #############

    # Particle/Field diagnostic options
    if particle_diagnostic_switch:
        particleperiod = 250  # TEMP
        particle_diagnostic_0 = ParticleDiagnostic(
            period=particleperiod,
            top=top,
            w3d=w3d,
            species={species.name: species
                     for species in listofallspecies},
            # if species.name == 'measurement'}, # TEMP
            comm_world=comm_world,
            lparallel_output=False,
            write_dir=diagDir[:-5])
        installafterstep(particle_diagnostic_0.write)

    if field_diagnostic_switch:
        fieldperiod = 1000
        efield_diagnostic_0 = FieldDiagnostic.ElectrostaticFields(
            solver=solverE,
            top=top,
            w3d=w3d,
            comm_world=comm_world,
            period=fieldperiod)
        installafterstep(efield_diagnostic_0.write)

    # Set externally derived parameters for efficiency calculation
    efficiency.tec_parameters['A_em'][0] = cathode_area * 1e4  # cm**2
    if install_grid:
        efficiency.tec_parameters['occlusion'][
            0] = efficiency.calculate_occlusion(**efficiency.tec_parameters)
    else:
        efficiency.tec_parameters['occlusion'][0] = 0.0

    ##########################
    # SOLVER SETTINGS/GENERATE
    ##########################

    # prevent gist from starting upon setup
    top.lprntpara = false
    top.lpsplots = false

    top.verbosity = -1  # Reduce solver verbosity
    solverE.mgverbose = -1  # further reduce output upon stepping - prevents websocket timeouts in Jupyter notebook

    init_iters = 20000
    regular_iters = 200

    init_tol = 1e-6
    regular_tol = 1e-6

    # Time Step

    # Determine an appropriate time step based upon estimated final velocity
    if install_grid:
        vz_accel = sqrt(2. * abs(V_grid) * np.abs(background_beam.charge) /
                        background_beam.mass)
    else:
        vz_accel = sqrt(2. * abs(collector_voltage) *
                        np.abs(background_beam.charge) / background_beam.mass)
    vzfinal = vz_accel + beam_beta * c
    dt = dz / vzfinal
    top.dt = dt

    solverE.mgmaxiters = init_iters
    solverE.mgtol = init_tol
    package("w3d")
    generate()
    solverE.mgtol = regular_tol
    solverE.mgmaxiters = regular_iters

    print("weights (background) (measurement): {}, {}".format(
        background_beam.sw, measurement_beam.sw))

    # Use rnpinject to set number of macroparticles emitted
    background_beam.rnpinject = PTCL_PER_STEP
    measurement_beam.rnpinject = 0  # measurement beam is off at start

    ##################
    # CONTROL SEQUENCE
    ##################
    # Run until steady state is achieved (flat current profile at collector) (measurement species turned on)
    # Record data for effiency calculation
    # Switch off measurement species and wait for simulation to clear (background species is switched on)

    early_abort = 0  # If true will flag output data to notify
    startup_time = 4 * gap_distance / vz_accel  # ~4 crossing times to approach steady-state with external circuit
    crossing_measurements = 10  # Number of crossing times to record for
    steps_per_crossing = int(gap_distance / vz_accel / dt)
    ss_check_interval = int(steps_per_crossing / 2.)
    ss_max_checks = 8  # Maximum number of of times to run steady-state check procedure before aborting
    times = []  # Write out timing of cycle steps to file
    clock = 0  # clock tracks the current, total simulation-runtime

    # Run initial block of steps
    record_time(stept, times, startup_time)
    clock += times[-1]
    stop_initialization = top.it  # for diag file

    print("Completed Initialization on Step {}\nInitialization run time: {}".
          format(top.it, times[-1]))

    # Start checking for Steady State Operation
    tol = 0.01
    ss_flag = 0
    check_count = 0  # Track number of times steady-state check performed

    while ss_flag != 1 and check_count < ss_max_checks:
        if (max_wall_time - clock) < times[-1]:
            early_abort = 1
            break

        record_time(step, times, ss_check_interval * 4)
        clock += times[-1]

        tstart = (top.it - ss_check_interval) * top.dt
        _, current1 = plate.get_current_history(js=None,
                                                l_lost=1,
                                                l_emit=0,
                                                l_image=0,
                                                tmin=tstart,
                                                tmax=None,
                                                nt=1)
        current = np.sum(current1)

        if np.abs(
                current
        ) < 0.5 * efficiency.tec_parameters['occlusion'][0] * beam_current:
            # If too little current is getting through run another check cycle
            check_count += 1
            print(
                "Completed check {}, insufficient current, running again for {} steps"
                .format(check_count, ss_check_interval))
            continue

        ss_flag = 1
        # print np.abs(current), 0.5 * efficiency.tec_parameters['occlusion'][0] * beam_current
        # try:
        #     # If steady_state check initialized no need to do it again
        #     steady_state
        # except NameError:
        #     # If this is the first pass with sufficient current then initialize the check
        #     if check_count == 0:
        #         # If the initial period was long enough to get current on collector then use that
        #         steady_state = SteadyState(top, plate, steps_per_crossing)
        #     else:
        #         # If we had to run several steady state checks with no current then just use the period with current
        #         steady_state = SteadyState(top, plate, ss_check_interval)
        #
        # ss_flag = steady_state(steps_per_crossing)
        check_count += 1

    stop_ss_check = top.it  # For diag file

    # If there was a failure to reach steady state after specified number of checks then pass directly end
    if check_count == ss_max_checks:
        early_abort = -1
        crossing_measurements = 0
        print("Failed to reach steady state. Aborting simulation.")
    else:
        # Start Steady State Operation
        print(
            " Steady State Reached.\nStarting efficiency "
            "recording for {} crossing times.\nThis will be {} steps".format(
                crossing_measurements,
                steps_per_crossing * crossing_measurements))

    # particle_diagnostic_0.period = steps_per_crossing #TEMP commented out
    # Switch to measurement beam species
    measurement_beam.rnpinject = PTCL_PER_STEP
    background_beam.rnpinject = 0

    # Install Zcrossing Diagnostic
    ZCross = ZCrossingParticles(zz=grid_height * gap_distance / 200.,
                                laccumulate=1)
    emitter_flux = []

    crossing_wall_time = times[
        -1] * steps_per_crossing / ss_check_interval  # Estimate wall time for one crossing
    print('crossing_wall_time estimate: {}, for {} steps'.format(
        crossing_wall_time, steps_per_crossing))
    print('wind-down loop time estimate: {}, for {} steps'.format(
        crossing_wall_time * steps_per_crossing / ss_check_interval,
        ss_check_interval))
    for sint in range(crossing_measurements):
        # Kill the loop and proceed to writeout if we don't have time to complete the loop
        if (max_wall_time - clock) < crossing_wall_time:
            early_abort = 2
            break

        record_time(step, times, steps_per_crossing)
        clock += times[-1]

        # Re-evaluate time for next loop
        crossing_wall_time = times[-1]

        # Record velocities of emitted particles for later KE calculation
        velocity_array = np.array([
            ZCross.getvx(js=measurement_beam.js),
            ZCross.getvy(js=measurement_beam.js),
            ZCross.getvz(js=measurement_beam.js)
        ]).transpose()
        # velocity_array = velocity_array[velocity_array[:, 2] >= 0.]  # Filter particles moving to emitter
        emitter_flux.append(velocity_array)

        ZCross.clear()  # Clear ZcrossingParticles memory

        print(
            "Measurement: {} of {} intervals completed. Interval run time: {} s"
            .format(sint + 1, crossing_measurements, times[-1]))
    stop_eff_calc = top.it  # For diag file
    # Run wind-down until measurement particles have cleared
    measurement_beam.rnpinject = 0
    background_beam.rnpinject = PTCL_PER_STEP

    initial_population = measurement_beam.npsim[0]
    measurement_tol = 0.03
    # if particle_diagnostic_switch:
    #     particle_diagnostic_0.period = ss_check_interval
    while measurement_beam.npsim[0] > measurement_tol * initial_population:
        # Kill the loop and proceed to writeout if we don't have time to complete the loop
        if (max_wall_time - clock
            ) < crossing_wall_time * ss_check_interval / steps_per_crossing:
            early_abort = 3
            break

        record_time(step, times, ss_check_interval)
        clock += times[-1]

        # Record velocities of emitted particles for later KE calculation
        # Check is required here as measurement_beam particles will not always be passing through
        if ZCross.getvx(js=measurement_beam.js).shape[0] > 0:
            velocity_array = np.array([
                ZCross.getvx(js=measurement_beam.js),
                ZCross.getvy(js=measurement_beam.js),
                ZCross.getvz(js=measurement_beam.js)
            ]).transpose()
            print "Backwards particles: {}".format(
                np.where(velocity_array[:, 2] < 0.)[0].shape[0])
            # velocity_array = velocity_array[velocity_array[:, 2] >= 0.]  # Filter particles moving to emitter
            emitter_flux.append(velocity_array)
            ZCross.clear()  # Clear ZcrossingParticles memory
        print(" Wind-down: Taking {} steps, On Step: {}, {} Particles Left".
              format(ss_check_interval, top.it, measurement_beam.npsim[0]))

    stop_winddown = top.it  # For diag file

    ######################
    # CALCULATE EFFICIENCY
    ######################
    try:
        emitter_flux = np.vstack(emitter_flux)
    except ValueError:
        # If this triggered then measurement emission never took place
        # Run took too long probably and abort took place
        emitter_flux = np.array([[0., 0., 0.]])

    # Find integrated charge on each conductor
    surface_charge = analyze_scraped_particles(top, measurement_beam, solverE)
    measured_charge = {}

    for key in surface_charge:
        # We can abuse the fact that js=0 for background species to filter it from the sum
        measured_charge[key] = np.sum(surface_charge[key][:, 1] *
                                      surface_charge[key][:, 3])

    # Set derived parameters from simulation
    efficiency.tec_parameters['run_time'][
        0] = crossing_measurements * steps_per_crossing * dt
    if crossing_measurements == 0:
        # Set to large value to force all powers and currents to zero
        efficiency.tec_parameters['run_time'][0] = 1e20

    # Find total number of measurement particles that were emitted
    total_macroparticles = measurement_beam.npsim[0] + np.sum(
        [measured_charge[key] for key in surface_charge])
    efficiency.tec_parameters['J_em'][0] = e * (total_macroparticles - measured_charge[scraper_dictionary['source']]) \
                                        * measurement_beam.sw / \
                                        efficiency.tec_parameters['run_time'][0] / efficiency.tec_parameters['A_em'][0]

    # If grid isn't being used then J_grid will not be in scraper dict
    try:
        efficiency.tec_parameters['J_grid'][0] = e * measured_charge[scraper_dictionary['grid']] * measurement_beam.sw / \
                                            efficiency.tec_parameters['run_time'][0] / \
                                            (efficiency.tec_parameters['occlusion'][0] *
                                             efficiency.tec_parameters['A_em'][0])
    except KeyError:
        efficiency.tec_parameters['J_grid'][0] = 0.0

    efficiency.tec_parameters['J_ec'][0] = e * measured_charge[scraper_dictionary['collector']] * measurement_beam.sw / \
                                        efficiency.tec_parameters['run_time'][0] / efficiency.tec_parameters['A_em'][0]

    efficiency.tec_parameters['P_em'][0] = efficiency.calculate_power_flux(
        emitter_flux, measurement_beam.sw,
        efficiency.tec_parameters['phi_em'][0], **efficiency.tec_parameters)

    # Efficiency calculation
    print("Efficiency")
    efficiency_result = efficiency.calculate_efficiency(
        **efficiency.tec_parameters)
    print("Overall Efficiency: {}".format(efficiency_result['eta']))
    print("Total steps: {}".format(top.it))
    ######################
    # FINAL RUN STATISTICS
    ######################

    if comm_world.rank == 0:
        if not os.path.exists('diags_id{}'.format(run_id)):
            os.makedirs('diags_id{}'.format(run_id))

        np.save('iv_data.npy',
                np.array([circuit.current_history, circuit.voltage_history]))

        write_parameter_file(run_attributes,
                             filename='diags_id{}/'.format(run_id))

        filename = 'efficiency_id{}.h5'.format(str(run_id))
        with h5.File(os.path.join('diags_id{}'.format(run_id), filename),
                     'w') as h5file:
            # TODO: Add current history
            eff_group = h5file.create_group('/efficiency')
            run_group = h5file.create_group('/attributes')
            scrap_group = h5file.create_group('/scraper')
            h5file.attrs['complete'] = early_abort
            for key in efficiency_result:
                eff_group.attrs[key] = efficiency_result[key]
            for key in efficiency.tec_parameters:
                eff_group.attrs[key] = efficiency.tec_parameters[key]
            for key in run_attributes:
                run_group.attrs[key] = run_attributes[key]
            run_group.attrs['dt'] = top.dt
            run_group.attrs['stop_initialization'] = stop_initialization
            run_group.attrs['stop_ss_check'] = stop_ss_check
            run_group.attrs['stop_eff_calc'] = stop_eff_calc
            run_group.attrs['stop_winddown'] = stop_winddown
            # for key, value in scraper_dictionary.iteritems():
            #     scrap_group.attrs[key] = measured_charge[value]
            #
            inv_scraper_dict = {
                value: key
                for key, value in scraper_dictionary.iteritems()
            }
            for cond in solverE.conductordatalist:
                cond_objs = cond[0]
                scrap_group.attrs[inv_scraper_dict[
                    cond_objs.condid]] = measured_charge[cond_objs.condid]
                _, bckgrnd_current = cond_objs.get_current_history(js=0,
                                                                   l_lost=1,
                                                                   l_emit=0,
                                                                   l_image=0,
                                                                   tmin=None,
                                                                   tmax=None,
                                                                   nt=top.it)
                _, msrmnt_current = cond_objs.get_current_history(js=1,
                                                                  l_lost=1,
                                                                  l_emit=0,
                                                                  l_image=0,
                                                                  tmin=None,
                                                                  tmax=None,
                                                                  nt=top.it)
                scrap_group.create_dataset('{}_background'.format(
                    inv_scraper_dict[cond_objs.condid]),
                                           data=bckgrnd_current)
                scrap_group.create_dataset('{}_measurement'.format(
                    inv_scraper_dict[cond_objs.condid]),
                                           data=msrmnt_current)

            h5file.create_dataset('times', data=times)
Пример #5
0
def test_drifted_plasmas():
    """
  main function for the case test_drifted_plasmas
  
  """

    # Picsar flag: 0 warp routines, 1 picsar routines
    l_pxr = 1
    l_temporal_diags = 0
    l_pytest = 0
    # --- flags turning off unnecessary diagnostics (ignore for now)
    top.ifzmmnt = 0
    top.itmomnts = 0
    top.itplps = 0
    top.itplfreq = 0
    top.zzmomnts = 0
    top.zzplps = 0
    top.zzplfreq = 0
    top.nhist = top.nt
    top.iflabwn = 0
    w3d.lrhodia3d = false
    w3d.lgetese3d = false
    w3d.lgtlchg3d = false

    #-------------------------------------------------------------------------------
    # Parameters
    #-------------------------------------------------------------------------------

    # Number of iterations
    Nsteps = 100

    #Mesh: normalized at the plasma frequency
    dx = 0.04
    dy = 0.04
    dz = 0.04
    dt = 0.9 * 1. / sqrt(1. / dx**2 + 1. / dy**2 + 1. / dz**2)

    # Plasma properties
    plasma_elec_density = 0.01
    nppcell = 5

    #Laser at the left border:
    a0 = 1.
    laser_duration = 10
    laser_width = 4 / 2  #(=2w_0)
    #S-pol
    #Transverse profile - Gaussian
    #Longitudinal profile Super-Gaussian 12
    #focused at x=6 from the left border

    # --- scaling

    #-------------------------------------------------------------------------------
    # main parameters
    #-------------------------------------------------------------------------------
    dim = "3d"  # 3D calculation
    #dim = "2d"                 # 2D calculation
    #dim = "1d"                 # 1D calculation
    dpi = 100  # graphics resolution
    l_test = 1  # Will open output window on screen
    # and stop before entering main loop.
    l_gist = 0  # Turns gist plotting on/off
    l_matplotlib = 1
    l_restart = false  # To restart simulation from an old run (works?)
    restart_dump = ""  # dump file to restart from (works?)
    l_moving_window = 1  # on/off (Galilean) moving window
    l_plasma = 1  # on/off plasma
    l_usesavedist = 0  # if on, uses dump of beam particles distribution
    l_smooth = 0  # on/off smoothing of current density
    l_laser = 0  # on/off laser
    l_pdump = 0  # on/off regular dump of beam data
    stencil = 0  # 0 = Yee; 1 = Yee-enlarged (Karkkainen) on EF,B; 2 = Yee-enlarged (Karkkainen) on E,F
    # use 0 or 1; 2 does not verify Gauss Law
    if dim == "1d": stencil = 0
    dtcoef = 1.  # coefficient to multiply default time step that is set at the EM solver CFL
    top.depos_order = 3  # particles deposition order (1=linear, 2=quadratic, 3=cubic)
    top.efetch = 4  # field gather type (1=from nodes "momentum conserving"; 4=from Yee mesh "energy conserving")

    top.runid = "Test_drifted_plasma"  # run name
    top.pline1 = "Test"  # comment line on plots
    top.runmaker = "J.L. Vay, M. Lobet"  # run makers
    top.lrelativ = true  # on/off relativity (for particles push)
    top.pgroup.lebcancel_pusher = 0  # flag for particle pusher (0=Boris pusher; 1=Vay PoP 08 pusher)
    #top.ibpush=2
    l_verbose = 0  # verbosity level (0=off; 1=on)

    #-------------------------------------------------------------------------------
    # diagnostics parameters + a few other settings
    #-------------------------------------------------------------------------------
    live_plot_freq = 1  # frequency (in time steps) of live plots (off is l_test is off)

    fielddiag_period = 500
    partdiag_period = 500

    #-------------------------------------------------------------------------------
    # laser parameters
    #-------------------------------------------------------------------------------
    # --- in lab frame
    lambda_laser = 1.e-6  # wavelength
    laser_width *= lambda_laser
    laser_waist = laser_width / 2
    laser_radius = laser_waist / 2.354820  # FWHM -> radius
    laser_duration = laser_duration * lambda_laser / clight  # laser duration
    laser_polangle = 0  #pi/2                       # polarization (0=aligned with x; pi/2=aligned with y)
    k0 = 2. * pi / lambda_laser
    w0 = k0 * clight
    ZR = 0.5 * k0 * (laser_waist**2)  # Rayleigh length
    Eamp = a0 * w0 * emass * clight / echarge
    Bamp = Eamp / clight
    if l_laser == 0: Eamp = Bamp = 0.

    #-------------------------------------------------------------------------------
    # plasma layers
    #-------------------------------------------------------------------------------
    dfact = 1.  # coefficient factor for plasma density (for scaled simulations)
    densc = emass * eps0 * w0**2 / echarge**2  # critical density

    #-------------------------------------------------------------------------------
    # Carbon plasma
    #-------------------------------------------------------------------------------
    dens0 = plasma_elec_density * densc  # plasma density
    wp = sqrt(dens0 * echarge**2 / (eps0 * emass))  # plasma frequency
    kp = wp / clight  # plasma wavenumber
    lambda_plasma = 2. * pi / kp  # plasma wavelength
    Tplasma = 2. * pi / wp  # plasma period

    #-------------------------------------------------------------------------------
    # print some plasma parameters to the screen
    #-------------------------------------------------------------------------------
    print " dx: ", dx, "dy: ", dy, "dz: ", dz, "dt: ", dt
    print " Plasma elec. density: ", plasma_elec_density, 'nc', dens0
    print " Plasma wavelength: ", lambda_plasma
    print " Plasma frequency: ", wp
    print ' Plasma period:', Tplasma

    #-------------------------------------------------------------------------------
    # number of plasma macro-particles/cell
    #-------------------------------------------------------------------------------
    nppcellx = 1  #5
    nppcelly = 1  #5
    nppcellz = 1  #5

    #-------------------------------------------------------------------------------
    # Algorithm choices
    # See Doxygen doc for more information
    #-------------------------------------------------------------------------------
    # Optional: current deposition algorithm,
    currdepo = 0
    # Optional: mpi com for the current desposition
    mpicom_curr = 0
    # Field gathering method
    fieldgathe = 0
    # Type of particle communication
    partcom = 0
    # Field gathering and particle pusher together
    fg_p_pp_separated = 0

    #-------------------------------------------------------------------------------
    # grid dimensions, nb cells and BC
    #-------------------------------------------------------------------------------
    w3d.zmmin = -2. * lambda_plasma
    w3d.zmmax = -w3d.zmmin
    w3d.xmmin = -2. * lambda_plasma
    w3d.xmmax = -w3d.xmmin
    w3d.ymmin = -2. * lambda_plasma
    w3d.ymmax = -w3d.ymmin

    w3d.nx = nint((w3d.xmmax - w3d.xmmin) / (dx * lambda_plasma))
    w3d.ny = nint((w3d.ymmax - w3d.ymmin) / (dy * lambda_plasma))
    w3d.nz = nint((w3d.zmmax - w3d.zmmin) / (dz * lambda_plasma))

    w3d.dx = (w3d.xmmax - w3d.xmmin) / w3d.nx
    w3d.dy = (w3d.ymmax - w3d.ymmin) / w3d.ny
    w3d.dz = (w3d.zmmax - w3d.zmmin) / w3d.nz

    # --- sets field boundary conditions
    # --- longitudinal
    w3d.bound0 = w3d.boundnz = periodic
    # --- transverse
    w3d.boundxy = periodic

    # --- sets particles boundary conditions
    # --- longitudinal
    top.pbound0 = periodic
    top.pboundnz = periodic
    # --- transverse
    top.pboundxy = periodic

    #-------------------------------------------------------------------------------
    # set graphics
    #-------------------------------------------------------------------------------
    if l_gist:
        if l_test:
            winon(0, dpi=dpi)
        else:
            setup()
    else:
        setup()

    #-------------------------------------------------------------------------------
    # set particles weights
    #-------------------------------------------------------------------------------
    weight = dens0 * w3d.dx * w3d.dy * w3d.dz / (nppcellx * nppcelly *
                                                 nppcellz)
    top.wpid = nextpid()  # Activate variable weights in the method addpart

    # --- create plasma species
    electron0 = Species(type=Electron, weight=weight, name='electron0')
    positron0 = Species(type=Positron, weight=weight, name='positron0')
    electron1 = Species(type=Electron, weight=weight, name='electron1')
    positron1 = Species(type=Positron, weight=weight, name='positron1')
    electron2 = Species(type=Electron, weight=weight, name='electron2')
    positron2 = Species(type=Positron, weight=weight, name='positron2')

    # --- Init the sorting
    sort = Sorting(periods=[10, 10, 10, 10],
                   starts=[0, 0, 0, 0],
                   activated=1,
                   dx=0.5,
                   dy=0.5,
                   dz=0.5,
                   xshift=-0.5,
                   yshift=-0.5,
                   zshift=-0.5)

    top.depos_order[...] = top.depos_order[
        0, 0]  # sets deposition order of all species = those of species 0
    top.efetch[...] = top.efetch[0]  # same for field gathering

    #-------------------------------------------------------------------------------
    # set smoothing of current density
    #-------------------------------------------------------------------------------
    if l_smooth:
        # --- 1 time nilinear (0.25,0.5,0.25) + 1 time relocalization (-1, 3/2,-1.)
        npass_smooth = [[1, 1], [0, 0], [1, 1]]
        alpha_smooth = [[0.5, 3. / 2], [0.5, 3.], [0.5, 3. / 2]]
        stride_smooth = [[1, 1], [1, 1], [1, 1]]
    else:
        npass_smooth = [[0], [0], [0]]
        alpha_smooth = [[1.], [1.], [1.]]
        stride_smooth = [[1], [1], [1]]

    #-------------------------------------------------------------------------------
    # initializes WARP
    #-------------------------------------------------------------------------------
    top.fstype = -1  # sets field solver to None (desactivates electrostatic solver)
    package('w3d')
    generate()
    #-------------------------------------------------------------------------------
    # set a few shortcuts
    #-------------------------------------------------------------------------------
    pg = top.pgroup

    if l_plasma:

        spatial_extent = 0.05
        speed = 0.9 * clight

        zmin = w3d.zmmin * spatial_extent
        zmax = w3d.zmmax * spatial_extent
        xmin = w3d.xmmin * spatial_extent
        xmax = w3d.xmmax * spatial_extent
        ymin = w3d.ymmin * spatial_extent
        ymax = w3d.ymmax * spatial_extent

        np = w3d.nx * w3d.ny * nint(
            (zmax - zmin) / w3d.dz) * nppcellx * nppcelly * nppcellz

        electron0.add_uniform_box(np,
                                  xmin,
                                  xmax,
                                  ymin,
                                  ymax,
                                  zmin,
                                  zmax,
                                  vzmean=speed,
                                  vthx=0.,
                                  vthy=0.,
                                  vthz=0.,
                                  spacing='uniform')
        positron0.add_uniform_box(np,
                                  xmin,
                                  xmax,
                                  ymin,
                                  ymax,
                                  zmin,
                                  zmax,
                                  vzmean=speed,
                                  vthx=0.,
                                  vthy=0.,
                                  vthz=0.,
                                  spacing='uniform')

        electron1.add_uniform_box(np,
                                  xmin,
                                  xmax,
                                  ymin,
                                  ymax,
                                  zmin,
                                  zmax,
                                  vymean=speed,
                                  vthx=0.,
                                  vthy=0.,
                                  vthz=0.,
                                  spacing='uniform')
        positron1.add_uniform_box(np,
                                  xmin,
                                  xmax,
                                  ymin,
                                  ymax,
                                  zmin,
                                  zmax,
                                  vymean=speed,
                                  vthx=0.,
                                  vthy=0.,
                                  vthz=0.,
                                  spacing='uniform')

        electron2.add_uniform_box(np,
                                  xmin,
                                  xmax,
                                  ymin,
                                  ymax,
                                  zmin,
                                  zmax,
                                  vxmean=speed,
                                  vthx=0.,
                                  vthy=0.,
                                  vthz=0.,
                                  spacing='uniform')
        positron2.add_uniform_box(np,
                                  xmin,
                                  xmax,
                                  ymin,
                                  ymax,
                                  zmin,
                                  zmax,
                                  vxmean=speed,
                                  vthx=0.,
                                  vthy=0.,
                                  vthz=0.,
                                  spacing='uniform')

    laser_total_duration = 1.25 * laser_duration

    #-------------------------------------------------------------------------------
    # set laser pulse shape
    #-------------------------------------------------------------------------------
    def laser_amplitude(time):
        global laser_total_duration, Eamp
        #fx=Exp[-((x-t)*2/xblen)]^12
        #xblen=10 - duration of the pulse
        return Eamp * exp(-(2 * (time - 0.5 * laser_total_duration) /
                            laser_duration)**12)

    def laser_profile(x, y, z):
        global laser_waist, ZR
        #fy=Exp[-(y*2/yblen)^2]
        #yblen=4
        r2 = x**2 + y**2
        W0 = laser_waist
        Wz = W0 * sqrt(
            1. + (z / ZR)**2)  # Beam radius varies along propagation direction
        return (W0 / Wz) * exp(-r2 / Wz**2)

    #-------------------------------------------------------------------------------
    # set laser amplitude by combining the pulse shape, laser profile, and laser phase
    #-------------------------------------------------------------------------------

    if l_laser:
        laser_source_z = 10 * w3d.dz
    else:
        laser_func = laser_source_z = Eamp = None

    #-------------------------------------------------------------------------------
    # initializes main field solver block
    #-------------------------------------------------------------------------------
    if l_pxr:
        ntilex = max(1, w3d.nxlocal / 10)
        ntiley = max(1, w3d.nylocal / 10)
        ntilez = max(1, w3d.nzlocal / 10)
        top.nextpid()
        top.nextpid()
        #    pg.sw=0.
        em = EM3DPXR(
            laser_func=laser_func,
            laser_source_z=laser_source_z,
            laser_polangle=laser_polangle,
            laser_emax=Eamp,
            stencil=stencil,
            npass_smooth=npass_smooth,
            alpha_smooth=alpha_smooth,
            stride_smooth=stride_smooth,
            l_2dxz=dim == "2d",
            l_1dz=dim == "1d",
            dtcoef=dtcoef,
            l_getrho=1,
            spectral=0,
            current_cor=0,
            listofallspecies=listofallspecies,
            ntilex=ntilex,
            ntiley=ntiley,
            ntilez=ntilez,
            # Guard cells
            #nxguard=6,
            #nyguard=6,
            #nzguard=6,
            currdepo=currdepo,
            mpicom_curr=mpicom_curr,
            fieldgathe=fieldgathe,
            sorting=sort,
            partcom=partcom,
            fg_p_pp_separated=fg_p_pp_separated,
            l_verbose=l_verbose,
            l_debug=0)
        step = em.step
    else:
        print ' em=EM3D'
        em = EM3D(laser_func=laser_func,
                  laser_source_z=laser_source_z,
                  laser_polangle=laser_polangle,
                  laser_emax=Eamp,
                  stencil=stencil,
                  npass_smooth=npass_smooth,
                  alpha_smooth=alpha_smooth,
                  stride_smooth=stride_smooth,
                  l_2dxz=dim == "2d",
                  l_1dz=dim == "1d",
                  dtcoef=dtcoef,
                  l_getrho=1,
                  l_pushf=1,
                  l_verbose=l_verbose)

    #-------------------------------------------------------------------------------
    # restarts from dump file
    #-------------------------------------------------------------------------------
    if l_restart:
        restore(dump_file)

    #-------------------------------------------------------------------------------
    # register solver
    #-------------------------------------------------------------------------------
    print ' register solver'
    registersolver(em)
    em.finalize()
    loadrho()

    print 'done'

    # ______________________________________________________________________________
    # Diagnostics
    # ______________________________________________________________________________

    t = 0
    imu0 = 12.566370614E-7
    t_array = []
    e0kinE_array = []
    p0kinE_array = []
    e1kinE_array = []
    p1kinE_array = []
    e2kinE_array = []
    p2kinE_array = []
    ezE_array = []
    eyE_array = []
    exE_array = []
    bzE_array = []
    byE_array = []
    bxE_array = []
    div_array = []
    etot_array = []

    # ______________________________________________________________________________
    # User actions at each iteration
    def liveplots():
        if top.it % live_plot_freq == 0:
            fma(0)
            em.pfez(view=3,
                    titles=0,
                    xscale=1. / lambda_plasma,
                    yscale=1. / lambda_plasma,
                    gridscale=1.e-12,
                    l_transpose=1,
                    direction=1)
            ptitles('Ez [TV/m]', 'Z [lambda]', 'X [lambda]')

            density = electron0.get_density()
            density = density[:, w3d.ny / 2, :]
            ppg(transpose(density),
                view=4,
                titles=0,
                xmin=w3d.zmmin + top.zgrid,
                xmax=w3d.zmmax + top.zgrid,
                ymin=w3d.xmmin,
                ymax=w3d.xmmax,
                xscale=1e6,
                yscale=1.e6)  #,gridscale=1./dens0)

            density = positron0.get_density()
            density = density[:, w3d.ny / 2, :]
            ppg(transpose(density),
                view=5,
                titles=0,
                xmin=w3d.zmmin + top.zgrid,
                xmax=w3d.zmmax + top.zgrid,
                ymin=w3d.xmmin,
                ymax=w3d.xmmax,
                xscale=1e6,
                yscale=1.e6)  #,gridscale=1./dens0)

        if (l_temporal_diags):

            # With Picsar
            if l_pxr:
                # Kinetic energy
                # Using python
                if False:
                    e0kinE = 0
                    e1kinE = 0
                    e2kinE = 0
                    p0kinE = 0
                    p1kinE = 0
                    p2kinE = 0
                    for i in range(em.ntilez):
                        for j in range(em.ntiley):
                            for k in range(em.ntilex):
                                e0kinE += sum(
                                    (1. / electron0.pgroups[i][j][k].
                                     gaminv[0:electron0.pgroups[i][j][k].nps] -
                                     1.) * electron0.pgroups[i][j][k].pid[
                                         0:electron0.pgroups[i][j][k].nps,
                                         0]) * 9.10938215E-31 * 299792458.**2
                                e1kinE += sum(
                                    (1. / electron1.pgroups[i][j][k].
                                     gaminv[0:electron1.pgroups[i][j][k].nps] -
                                     1.) * electron1.pgroups[i][j][k].pid[
                                         0:electron1.pgroups[i][j][k].nps,
                                         0]) * 9.10938215E-31 * 299792458.**2
                                e2kinE += sum(
                                    (1. / electron2.pgroups[i][j][k].
                                     gaminv[0:electron2.pgroups[i][j][k].nps] -
                                     1.) * electron2.pgroups[i][j][k].pid[
                                         0:electron2.pgroups[i][j][k].nps,
                                         0]) * 9.10938215E-31 * 299792458.**2
                                p0kinE += sum(
                                    (1. / positron0.pgroups[i][j][k].
                                     gaminv[0:positron0.pgroups[i][j][k].nps] -
                                     1.) * positron0.pgroups[i][j][k].pid[
                                         0:positron0.pgroups[i][j][k].nps,
                                         0]) * 9.10938215E-31 * 299792458.**2
                                p1kinE += sum(
                                    (1. / positron1.pgroups[i][j][k].
                                     gaminv[0:positron1.pgroups[i][j][k].nps] -
                                     1.) * positron1.pgroups[i][j][k].pid[
                                         0:positron1.pgroups[i][j][k].nps,
                                         0]) * 9.10938215E-31 * 299792458.**2
                                p2kinE += sum(
                                    (1. / positron2.pgroups[i][j][k].
                                     gaminv[0:positron2.pgroups[i][j][k].nps] -
                                     1.) * positron2.pgroups[i][j][k].pid[
                                         0:positron2.pgroups[i][j][k].nps,
                                         0]) * 9.10938215E-31 * 299792458.**2
                else:
                    # Using the fortran subroutine
                    e0kinE = em.get_kinetic_energy(
                        1) * 9.10938215E-31 * 299792458.**2
                    e1kinE = em.get_kinetic_energy(
                        3) * 9.10938215E-31 * 299792458.**2
                    e2kinE = em.get_kinetic_energy(
                        5) * 9.10938215E-31 * 299792458.**2
                    p0kinE = em.get_kinetic_energy(
                        2) * 9.10938215E-31 * 299792458.**2
                    p1kinE = em.get_kinetic_energy(
                        4) * 9.10938215E-31 * 299792458.**2
                    p2kinE = em.get_kinetic_energy(
                        6) * 9.10938215E-31 * 299792458.**2

                print ' Electron kinetic energy (J)', e0kinE, e1kinE, e2kinE
                print ' Positron kinetic energy (J)', p0kinE, p1kinE, p2kinE

                # Electric energy
                # Using python
                if False:
                    ezE = 0.5 * sum(em.fields.Ez[0:em.nxlocal, 0:em.nylocal,
                                                 0:em.nzlocal]**
                                    2) * em.dx * em.dy * em.dz * 8.85418782E-12
                    exE = 0.5 * sum(em.fields.Ex[0:em.nxlocal, 0:em.nylocal,
                                                 0:em.nzlocal]**
                                    2) * em.dx * em.dy * em.dz * 8.85418782E-12
                    eyE = 0.5 * sum(em.fields.Ey[0:em.nxlocal, 0:em.nylocal,
                                                 0:em.nzlocal]**
                                    2) * em.dx * em.dy * em.dz * 8.85418782E-12
                    bzE = 0.5 * sum(em.fields.Bz[0:em.nxlocal, 0:em.nylocal,
                                                 0:em.nzlocal]**
                                    2) * em.dx * em.dy * em.dz * imu0
                    bxE = 0.5 * sum(em.fields.Bx[0:em.nxlocal, 0:em.nylocal,
                                                 0:em.nzlocal]**
                                    2) * em.dx * em.dy * em.dz * imu0
                    byE = 0.5 * sum(em.fields.By[0:em.nxlocal, 0:em.nylocal,
                                                 0:em.nzlocal]**
                                    2) * em.dx * em.dy * em.dz * imu0
                    div = 0
                    print ' Electric energy (J):', ezE, eyE, exE
                    print ' Magnetic energy (J):', bzE, byE, bxE
                # using picsar fortran subroutine
                else:
                    exE = em.get_field_energy('ex') * 8.85418782E-12
                    eyE = em.get_field_energy('ey') * 8.85418782E-12
                    ezE = em.get_field_energy('ez') * 8.85418782E-12
                    bxE = em.get_field_energy('bx') * 8.85418782E-12
                    byE = em.get_field_energy('by') * 8.85418782E-12
                    bzE = em.get_field_energy('bz') * 8.85418782E-12
                    div = em.get_normL2_divEeps0_rho()
                    print ' Electric energy (J):', ezE, eyE, exE
                    print ' Magnetic energy (J):', bzE, byE, bxE
                    print ' NormL2 of DivE*eps0 - rho:', div

                etot = ezE + exE + eyE
                etot += e0kinE + e1kinE + e2kinE
                etot += p0kinE + p1kinE + p2kinE
                etot += bzE + bxE + byE
                print ' Total energy (J)', etot

                # Put in arrays
                e0kinE_array.append(e0kinE)
                p0kinE_array.append(p0kinE)
                e1kinE_array.append(e1kinE)
                p1kinE_array.append(p1kinE)
                e2kinE_array.append(e2kinE)
                p2kinE_array.append(p2kinE)
                ezE_array.append(ezE)
                eyE_array.append(eyE)
                exE_array.append(exE)
                bzE_array.append(bzE)
                byE_array.append(byE)
                bxE_array.append(bxE)
                div_array.append(div)
                etot_array.append(etot)
                t_array.append(top.time)

            #With warp
            else:

                # Get divergence
                divE = em.getdive()
                rho = em.getrho()
                F = em.getf()
                divarray = divE * eps0 - rho
                div = LA.norm((divarray))
                maxdiv = abs(divarray).max()
                mindiv = abs(divarray).min()

                print ' NormL2 of DivE*eps0 - rho:', div, LA.norm(
                    F), 'Max', maxdiv, 'Min', mindiv

                #electron0.getn()      # selectron macro-particle number
                #x = electron0.getx()      # selectron macro-particle x-coordinates
                #y = electron0.gety()      # selectron macro-particle y-coordinates
                #z = electron0.getz()      # selectron macro-particle x-coordinates
                #pid = electron0.getpid()

                div_array.append(div)
                t_array.append(top.time)

    installafterstep(liveplots)

    # _____________________________________________________________________________
    #
    # Outputs
    # _____________________________________________________________________________

    # Setup the diagnostics
    diag_period = 10

    remove_existing_directory(['diags'])

    diag1 = FieldDiagnostic( period=diag_period, top=top, w3d=w3d, em=em,\
      comm_world=comm_world , write_dir='diags')

    installafterstep(diag1.write)

    diag2 = ParticleDiagnostic( period=diag_period, top=top, w3d=w3d, \
      species={ species.name : species for species in listofallspecies }, \
      comm_world=comm_world , write_dir='diags')

    installafterstep(diag2.write)

    tottime = AppendableArray()

    def accuttime():
        global tottime
        tottime.append(time.clock())
        if me == 0 and top.it % 200 == 0:
            f = PW.PW('tottime.pdb')
            f.time = tottime[:]
            f.close()

    #installafterstep(accuttime)

    print '\nInitialization complete\n'

    # ______________________________________________________________________________
    # running
    em.step(Nsteps, 1, 1)

    # ______________________________________________________________________________
    #
    # Checkings and analysis
    # ______________________________________________________________________________

    if me == 0:

        if (l_temporal_diags):

            # ______________________________________________________________________________
            # RCparams
            if l_matplotlib:
                mpl.rcParams['font.size'] = 15
                mpl.rcParams['legend.fontsize'] = 12
                mpl.rcParams['figure.facecolor'] = 'white'

            t_array = array(t_array)

            print ' Plasma period:', Tplasma

            # Plotting
            if l_matplotlib:
                fig = plt.figure(figsize=(16, 8))
                gs = gridspec.GridSpec(2, 2)
                ax = plt.subplot(gs[:, :])

                ax.plot(t_array, e0kinE_array, label='Elec. kin. energy')
                ax.plot(t_array, p0kinE_array, label='Posi. kin. energy')
                ax.plot(t_array, e1kinE_array, label='Elec. kin. energy')
                ax.plot(t_array, p1kinE_array, label='Posi. kin. energy')
                ax.plot(t_array, e2kinE_array, label='Elec. kin. energy')
                ax.plot(t_array, p2kinE_array, label='Posi. kin. energy')
                ax.plot(t_array, ezE_array, label='Ez energy')
                ax.plot(t_array, eyE_array, label='Ey energy')
                ax.plot(t_array, exE_array, label='Ex energy')
                ax.plot(t_array, bzE_array, label='Bz energy')
                ax.plot(t_array, byE_array, label='By energy')
                ax.plot(t_array, bxE_array, label='Bx energy')
                ax.plot(t_array,
                        etot_array,
                        label='Total energy',
                        color='k',
                        ls=':')

                ax.set_ylim([0, max(etot_array) * 1.1])

                ax.set_xlabel('t (s)')
                ax.set_ylabel('Energy (J)')

                ax.legend(loc='upper center',
                          ncol=4,
                          borderaxespad=-2,
                          fontsize=20)

            # _____________________________________________________________________
            # DivE*eps0 - rho
            if l_matplotlib:
                fig1 = plt.figure(figsize=(12, 8))
                gs1 = gridspec.GridSpec(2, 2)
                ax1 = plt.subplot(gs[:, :])

                ax1.plot(t_array,
                         div_array,
                         label=r'$\nabla E \times \varepsilon_0 - \rho$',
                         lw=2)
                ax1.legend(loc='upper center',
                           ncol=4,
                           borderaxespad=-2,
                           fontsize=20)

                ax1.set_xlabel('t (s)')

            if l_pytest:
                assert (max(div_array) <
                        1E-5), "L2 norm||DivE - rho/eps0|| too high"

        # _____________________________________________________________________
        # Advice

        print
        print ' _______________________________________'
        print ' Advice for users:'
        print ' - Check that the energy is constant with time'
        print ' - Check that divE = rho/eps0 for each tests'
        print ' - Check the energy oscillating behavior'
        print

        if l_matplotlib: plt.show()
Пример #6
0
######################
# Particle Diagnostics
######################

#wp.top.lsavelostparticles = True

# HDF5 Particle/Field diagnostic options

if particle_diagnostic_switch:
    particleperiod = 1000  # Particle diagnostic write frequency
    particle_diagnostic_0 = ParticleDiagnostic(
        period=particleperiod,
        top=wp.top,
        w3d=wp.w3d,  # Should always be set
        # Include data from all existing species in write
        species={species.name: species
                 for species in wp.listofallspecies},
        # Option for parallel write (if available on system)
        comm_world=wp.comm_world,
        lparallel_output=False,
        # `ParticleDiagnostic` automatically append 'hdf5' to path name
        write_dir=diagDir[:-5])
    wp.installafterstep(particle_diagnostic_0.write
                        )  # Write method is installed as an after-step action

if field_diagnostic_switch:
    fieldperiod = 1000  # Field diagnostic write frequency
    efield_diagnostic_0 = FieldDiagnostic.ElectrostaticFields(
        solver=solverE,
        top=wp.top,
        w3d=wp.w3d,
        comm_world=wp.comm_world,
Пример #7
0

installafterstep(liveplots)

# Load additional OpenPMD diagnostic
diag_f = FieldDiagnostic(period=fielddiag_period,
                         top=top,
                         w3d=w3d,
                         em=em,
                         comm_world=comm_world,
                         fieldtypes=["E", "B"],
                         lparallel_output=lparallelo)
diag_elec_C = ParticleDiagnostic(period=partdiag_period,
                                 top=top,
                                 w3d=w3d,
                                 species={"elec_C": elec_C},
                                 select={'ux': [0.1, None]},
                                 comm_world=comm_world,
                                 lparallel_output=lparallelo)
diag_ions_C = ParticleDiagnostic(period=partdiag_period,
                                 top=top,
                                 w3d=w3d,
                                 species={"ions_C": ions_C},
                                 select={'ux': [None, -0.1]},
                                 comm_world=comm_world,
                                 lparallel_output=lparallelo)
diag_elec_streak = ParticleDiagnostic(period=partdiag_period_probe,
                                      top=top,
                                      w3d=w3d,
                                      species={"elec_streak": elec_streak},
                                      particle_data={'position', 'B'},