def get_run():
    """Utility function to get the same run setup for all tests below."""

    # Initialize and import only when we know dimension
    run = diode_setup.DiodeRun_V1(GEOM_STR='XZ',
                                  CATHODE_TEMP=CATHODE_TEMP,
                                  CATHODE_PHI=CATHODE_PHI,
                                  V_ANODE_CATHODE=VOLTAGE,
                                  D_CA=D_CA,
                                  NPPC=4,
                                  NX=NX,
                                  NZ=NZ,
                                  DT=DT,
                                  TOTAL_TIMESTEPS=MAX_STEPS,
                                  DIAG_STEPS=DIAG_STEPS,
                                  P_INERT=P_INERT,
                                  T_ELEC=1100 + 273.15,
                                  INERT_GAS_TYPE="Ar",
                                  FIELD_DIAG_DATA_LIST=['phi'],
                                  PLASMA_DENSITY=10.2e12,
                                  SEED_NPPC=10)
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=True,
                  init_injectors=False,
                  init_neutral_plasma=True,
                  init_field_diag=True,
                  init_simcontrol=False,
                  init_warpx=False)
    return run
Exemplo n.º 2
0
    def setup_run(self):

        ####################################
        # Diode setup
        ####################################

        self.run = diode_setup.DiodeRun_V1(
            GEOM_STR='XZ',
            CATHODE_TEMP=self.CATHODE_TEMP,
            CATHODE_A=self.CATHODE_A,
            CATHODE_PHI=self.CATHODE_PHI,
            USE_SCHOTTKY=self.USE_SCHOTTKY,
            ANODE_TEMP=self.ANODE_TEMP,
            ANODE_PHI=self.ANODE_PHI,
            V_ANODE_CATHODE=self.V_ANODE_CATHODE,
            D_CA=self.D_CA,
            DT=self.DT,
            NX=self.NX,
            NZ=self.NZ,
            DIRECT_SOLVER=True,
            NPPC=self.NPPC,
            TOTAL_TIMESTEPS=self.TOTAL_TIMESTEPS,
            DIAG_STEPS=self.DIAG_STEPS)

        # Only the functions we change from defaults are listed here
        self.run.setup_run(init_runinfo=True,
                           init_fluxdiag=True,
                           init_simcontrol=True,
                           init_warpx=True)
Exemplo n.º 3
0
def test_write_results():
    test_name = "write_results_test"
    testing_util.initialize_testingdir(test_name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(83197410)

    STEPS = 1
    D_CA = 0.067 # m
    FREQ = 13.56e6 # MHz
    VOLTAGE = 450.0
    NX = 8
    NZ = 128
    DT = 1.0 / (400 * FREQ)

    run = diode_setup.DiodeRun_V1(
        GEOM_STR='XZ',
        V_ANODE_CATHODE=VOLTAGE,
        V_ANODE_EXPRESSION="%.1f*sin(2*pi*%.5e*t)" % (VOLTAGE, FREQ),
        D_CA=D_CA,
        INERT_GAS_TYPE='He',
        N_INERT=9.64e20,  # m^-3
        T_INERT=300.0,  # K
        PLASMA_DENSITY=2.56e14,  # m^-3
        T_ELEC=30000.0,  # K
        SEED_NPPC=10,
        NX=NX,
        NZ=NZ,
        DT=DT,
        TOTAL_TIMESTEPS=STEPS,
    )

    run.setup_run(
        init_conductors=False,
        init_scraper=False,
        init_injectors=False,
        init_neutral_plasma=True,
        init_simcontrol=True,
        init_warpx=True,
        init_simulation=True
    )

    def results_contents():
        return f"The dimensions of this run were: {NX} x {NZ}"

    run.control.set_write_func(results_contents)
    mwxrun.step(run.control)

    results_path = os.path.join(WarpXDiagnostic.DIAG_DIR, "results.txt")

    assert os.path.isfile(results_path)

    with open(results_path, 'r') as results_file:
        assert results_file.readline().strip() == f"The dimensions of this run were: {NX} x {NZ}"
Exemplo n.º 4
0
def run_simulation(V_bias, steps, save_current):

    radius_frac = 0.8

    ####################################
    # Diode setup
    ####################################

    run = diode_setup.DiodeRun_V1(
        GEOM_STR='RZ',
        CATHODE_TEMP=1100.0 + 273.15,  # K
        CATHODE_A=6e5,  # A/m^2/K^2
        CATHODE_PHI=2.11,  # eV
        USE_SCHOTTKY=False,
        ANODE_TEMP=200,  # K
        ANODE_PHI=1.4,  # eV
        V_ANODE_CATHODE=V_bias,  # V
        D_CA=50e-6,  # m
        DT=0.5e-12,  # s
        NX=32,
        NZ=128,
        DIRECT_SOLVER=False,
        NPPC=1,
        TOTAL_TIMESTEPS=steps,
        DIAG_STEPS=((steps // 5) if steps > 10 else steps),
    )

    # Only the functions we change from defaults are listed here
    run.setup_run(init_injectors=False)

    #################################
    # Setup cathode injector
    #################################

    run.emitter = emission.ZDiscEmitter(conductor=run.cathode,
                                        T=run.CATHODE_TEMP,
                                        outer_emission_radius=run.PERIOD *
                                        radius_frac,
                                        transverse_fac=run.TRANSVERSE_FAC)
    run.injector = emission.ThermionicInjector(run.emitter, run.electrons,
                                               run.NPPC, run.CATHODE_TEMP,
                                               run.CATHODE_PHI, run.CATHODE_A,
                                               run.USE_SCHOTTKY)

    #################################
    # Initialize WarpX and fluxdiags
    #################################

    run.init_runinfo()
    run.init_fluxdiag()
    run.init_warpx()

    #################################
    # Simulation run
    #################################

    mwxrun.simulation.step(steps)

    #################################
    # Save IV results
    #################################

    if save_current and mwxrun.me == 0:
        key = ('scrape', 'anode', 'electrons')
        J_diode = run.fluxdiag.ts_dict[key].get_averagevalue_by_key('J')
        # normalize appropriate
        J_diode *= 1.0 / radius_frac**2
        print(f'{V_bias}    {J_diode}')
        with open(f'results_d_{int(run.D_CA*1e6)}.dat', 'a') as f:
            f.write(f'{V_bias}    {J_diode}\n')
def test_particle_diag():
    test_name = "particle_diag_test_with_post_processing"
    testing_util.initialize_testingdir(test_name)

    # Initialize each run with consistent, randomly-chosen, rseed, Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(47239475)

    DT = 0.5e-12  # s

    P_INERT = 1  # torr
    T_INERT = 300  # K

    D_CA = 5e-4  # m
    VOLTAGE = 25  # V
    CATHODE_TEMP = 1100 + 273.15  # K
    CATHODE_PHI = 2.1  # work function in eV
    NX = 8
    NZ = 128

    max_steps = 10
    diag_steps = 2

    DATA_LIST = ['position', 'momentum', 'weighting']
    PLOT_SPECIES = ['electrons']
    DIAG_PLOT_DATA_LIST = ["particle_position_x", "particle_momentum_x"]

    run = diode_setup.DiodeRun_V1(
        GEOM_STR='XZ',
        CATHODE_TEMP=CATHODE_TEMP,
        CATHODE_PHI=CATHODE_PHI,
        V_ANODE_CATHODE=VOLTAGE,
        D_CA=D_CA,
        P_INERT=P_INERT,
        T_INERT=T_INERT,
        NPPC=50,
        NX=NX,
        NZ=NZ,
        DT=DT,
        TOTAL_TIMESTEPS=max_steps,
        DIAG_STEPS=diag_steps,
        PARTICLE_DIAG_DATA_LIST=DATA_LIST,
        PARTICLE_PLOT_SPECIES=PLOT_SPECIES,
        PARTICLE_DIAG_PLOT_DATA_LIST=DIAG_PLOT_DATA_LIST,
        PARTICLE_DIAG_PLOT_AFTER_RUN=True)
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=True,
                  init_particle_diag=True,
                  init_warpx=True)

    mwxrun.simulation.step(max_steps)

    # verify that the plot images were created.

    print('Verifying that all plots were created...')
    for i in range(diag_steps, max_steps - 1, diag_steps):
        for specimen in PLOT_SPECIES:
            for param in DIAG_PLOT_DATA_LIST:
                file_name = os.path.join(
                    run.particle_diag.write_dir,
                    specimen + '_' + param + f'_{i:05d}.png')
                print(file_name)
                assert os.path.isfile(file_name), f"{file_name} not found"
        print('All plots exist!')
def test_superLU_solver():
    name = "superLU_solver"
    # Include a random run number to allow parallel runs to not collide. Using
    # python randint prevents collisions due to numpy rseed below
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(92160881)

    # set to False to regenerate the reference data
    DIRECT_SOLVER = True

    # Specific numbers match older run for consistency
    FREQ = 13.56e6  # MHz
    DT = 1.0 / (400 * FREQ)
    DIAG_STEPS = 50
    DIAG_INTERVAL = DIAG_STEPS * DT
    VOLTAGE = 450.0
    D_CA = 0.067  # m
    NX = 16
    NZ = 128
    run = diode_setup.DiodeRun_V1(
        GEOM_STR='XZ',
        DIRECT_SOLVER=DIRECT_SOLVER,
        V_ANODE_EXPRESSION=f"{VOLTAGE}*sin(2*pi*{FREQ:.5e}*t)",
        D_CA=D_CA,
        INERT_GAS_TYPE='He',
        N_INERT=9.64e20,  # m^-3
        T_INERT=300.0,  # K
        PLASMA_DENSITY=2.56e14,  # m^-3
        T_ELEC=30000.0,  # K
        SEED_NPPC=16 * 32,
        NX=NX,
        NZ=NZ,
        DT=DT,
        TOTAL_TIMESTEPS=50,
        DIAG_STEPS=DIAG_STEPS,
        DIAG_INTERVAL=DIAG_INTERVAL)
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=True,
                  init_scraper=False,
                  init_injectors=False,
                  init_mcc=True,
                  init_neutral_plasma=True,
                  init_field_diag=False,
                  init_simcontrol=True,
                  init_warpx=True)

    # Run the main WARP loop
    while run.control.check_criteria():
        mwxrun.simulation.step()

    #######################################################################
    # Check phi results against reference data from MLMG solver           #
    #######################################################################

    phi_data = mwxrun.get_gathered_phi_grid(include_ghosts=False)
    data = np.mean(phi_data, axis=0)
    # uncomment to generate reference data
    # np.save('reference_data.npy', data)

    ref_data = np.load(
        os.path.join(testing_util.test_dir, 'direct_solver',
                     'reference_data.npy'))

    assert np.allclose(data, ref_data, rtol=0.001)
Exemplo n.º 7
0
def test_extra_pid(caplog):
    caplog.set_level(logging.INFO)
    name = "mespecies_extra_pid"
    # Include a random run number to allow parallel runs to not collide. Using
    # python randint prevents collisions due to numpy rseed below
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(9216001)

    # Specific numbers match older run for consistency
    DIAG_STEPS = 2
    D_CA = 0.05  # m
    NX = 16
    NZ = 128
    run = diode_setup.DiodeRun_V1(GEOM_STR='XZ',
                                  V_ANODE_CATHODE=450.0,
                                  D_CA=D_CA,
                                  NX=NX,
                                  NZ=NZ,
                                  DT=1.0e-10,
                                  TOTAL_TIMESTEPS=25,
                                  DIAG_STEPS=DIAG_STEPS,
                                  DIRECT_SOLVER=True)
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=True,
                  init_injectors=False,
                  init_simcontrol=True,
                  init_warpx=True)

    # add new pid for the ions
    run.electrons.add_pid('extra_pid')

    def check_particle_nums():
        return not (mwxrun.get_npart() < 950)

    nps = 1000
    w = np.random.randint(low=1, high=100, size=nps)
    mwxrun.sim_ext.add_particles(run.electrons.name,
                                 x=np.random.random(nps) * D_CA / NZ * NX,
                                 y=np.zeros(nps),
                                 z=np.random.random(nps) * D_CA,
                                 ux=np.random.normal(scale=1e4, size=nps),
                                 uy=np.random.normal(scale=1e4, size=nps),
                                 uz=np.random.normal(scale=1e4, size=nps),
                                 w=w,
                                 extra_pid=np.copy(w) * 10.0)

    run.control.add_checker(check_particle_nums)

    # Run the main WARP loop
    while run.control.check_criteria():
        mwxrun.simulation.step(DIAG_STEPS)

    #######################################################################
    # Cleanup and final output                                            #
    #######################################################################

    all_log_output = ""
    records = caplog.records

    for record in records:
        all_log_output += record.msg + "\n"

    # make sure out isn't empty
    outstr = "SimControl: Termination from criteria: check_particle_nums"
    assert outstr in all_log_output

    weights = run.electrons.get_array_from_pid('w')
    extra_pid = run.electrons.get_array_from_pid('extra_pid')
    for ii in range(len(weights)):
        assert np.allclose(extra_pid[ii] / weights[ii], 10.0)
Exemplo n.º 8
0
def test_field_diag(plot_on_diag_steps):
    # We test either post processing or plotting on diag steps, not both.
    post_processing = not plot_on_diag_steps

    plot_diag_str = "_with_diag_plotting" if plot_on_diag_steps else ""
    post_proc_str = "_with_post_processing" if post_processing else ""
    test_name = "field_diag_test" + plot_diag_str + post_proc_str

    testing_util.initialize_testingdir(test_name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(83197410)

    STEPS = 10
    D_CA = 0.067 # m
    FREQ = 13.56e6 # MHz
    VOLTAGE = 450.0
    DT = 1.0 / (400 * FREQ)
    DIAG_STEPS = 2 * (int(post_processing) + 1)
    DIAG_DATA_LIST = ['rho_electrons', 'rho_he_ions', 'phi']
    #DIAG_SPECIES_LIST = ["electrons", "he_ions"]
    DIAG_SPECIES_LIST = None

    run = diode_setup.DiodeRun_V1(
        GEOM_STR='XZ',
        V_ANODE_CATHODE=VOLTAGE,
        V_ANODE_EXPRESSION="%.1f*sin(2*pi*%.5e*t)" % (VOLTAGE, FREQ),
        D_CA=D_CA,
        INERT_GAS_TYPE='He',
        N_INERT=9.64e20,  # m^-3
        T_INERT=300.0,  # K
        PLASMA_DENSITY=2.56e14,  # m^-3
        T_ELEC=30000.0,  # K
        SEED_NPPC=10,
        NX=8,
        NZ=128,
        DT=DT,
        TOTAL_TIMESTEPS=STEPS,
        DIAG_STEPS=DIAG_STEPS,
        FIELD_DIAG_DATA_LIST=DIAG_DATA_LIST,
        FIELD_DIAG_SPECIES_LIST=DIAG_SPECIES_LIST,
        FIELD_DIAG_PLOT=plot_on_diag_steps,
        FIELD_DIAG_INSTALL_WARPX=post_processing,
        FIELD_DIAG_PLOT_AFTER_RUN=post_processing
    )

    run.setup_run(
        init_conductors=False,
        init_scraper=False,
        init_injectors=False,
        init_neutral_plasma=True,
        init_field_diag=True,
        init_warpx=True,
        init_simulation=True
    )
    mwxrun.simulation.step()

    # verify that the plot images were created.
    if plot_on_diag_steps:
        print("Verifying that all data and plot files were created...")
        phi_data_n = len(glob.glob(
            os.path.join(
                run.field_diag.write_dir, "Electrostatic_potential_*.npy"
            )
        ))
        phi_plots_n = len(glob.glob(
            os.path.join(
                run.field_diag.write_dir, "Electrostatic_potential_*.png"
            )
        ))
        assert phi_data_n == 5
        assert phi_plots_n == 5
        for species in [species.name for species in mwxrun.simulation.species]:
            n_data = len(glob.glob(
                os.path.join(
                    run.field_diag.write_dir, f"{species}_particle_density_*.npy"
                )
            ))
            n_plots = len(glob.glob(
                os.path.join(
                    run.field_diag.write_dir, f"{species}_particle_density_*.png"
                )
            ))
            assert n_data == 5
            assert n_plots == 5

        print("All plots exist!")

    # verify that the post processing image was created
    if post_processing:
        print("Verifying that all plots were created...")
        # Start at 1st diagnostic (at step 0 all data arrays are 0 and are
        # therefore skipped)
        for i in range(DIAG_STEPS, STEPS - 1, DIAG_STEPS):
            for param in DIAG_DATA_LIST:
                assert os.path.isfile(
                    os.path.join(
                        run.field_diag.write_dir, param + f"_{i:05d}.png"
                    )
                ), param + "_" + f"{i:06d}.png doesn't exist"

        print("All plots exist!")
Exemplo n.º 9
0
def test_injector_flux_diagnostic():
    name = "injectorfluxDiagnostic"
    # Include a random run number to allow parallel runs to not collide.  Using
    # python randint prevents collisions due to numpy rseed below
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed, Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(47239475)

    TOTAL_TIME = 1e-10  # s
    DIAG_INTERVAL = 1e-10  # s
    DT = 1e-12  # s

    P_INERT = 1  # torr
    T_INERT = 300  # K

    D_CA = 5e-4  # m
    VOLTAGE = 25  # V
    CATHODE_TEMP = 1100 + 273.15  # K
    CATHODE_PHI = 2.1  # work function in eV
    NX = 8
    NZ = 128

    DIRECT_SOLVER = True

    max_steps = int(TOTAL_TIME / DT)
    diag_steps = int(DIAG_INTERVAL / DT)

    run = diode_setup.DiodeRun_V1(GEOM_STR='XZ',
                                  CATHODE_TEMP=CATHODE_TEMP,
                                  CATHODE_PHI=CATHODE_PHI,
                                  V_ANODE_CATHODE=VOLTAGE,
                                  D_CA=D_CA,
                                  P_INERT=P_INERT,
                                  T_INERT=T_INERT,
                                  NPPC=50,
                                  NX=NX,
                                  NZ=NZ,
                                  DIRECT_SOLVER=DIRECT_SOLVER,
                                  DT=DT,
                                  TOTAL_TIMESTEPS=max_steps,
                                  DIAG_STEPS=diag_steps,
                                  DIAG_INTERVAL=DIAG_INTERVAL,
                                  CHECK_CHARGE_CONSERVATION=False)

    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=True,
                  init_scraper=True,
                  init_runinfo=True,
                  init_fluxdiag=False,
                  init_warpx=False)

    run.fluxdiag = flux_diagnostic.FluxDiagnostic(
        diag_steps=run.DIAG_STEPS,
        runinfo=run.runinfo,
        check_charge_conservation=run.CHECK_CHARGE_CONSERVATION,
        overwrite=False,
        save_csv=True)
    run.init_warpx()

    mwxrun.simulation.step(max_steps)

    # check that current in CSV is correct
    filename = "diags/fluxes/thermionic_injector_electrons_injected.csv"

    assert os.path.isfile(filename), "Could not find output CSV."

    df = pandas.read_csv(filename)

    q = df["q"]

    cathode_area = run.emitter.area
    J = mwxutil.J_RD(run.injector.T, run.injector.WF, run.injector.A)
    current = J * cathode_area * -1

    assert np.allclose(q / DT, current, rtol=0.01, atol=0)

    # check that pickle file current is correct
    with open("diags/fluxes/fluxdata_{:010d}.dpkl".format(100), "rb") as pfile:
        flux_diags = dill.load(pfile)

    # leave off first element (time step 0) where there is 0 current
    J_pickle = (flux_diags['fullhist_dict'][(
        'inject', 'cathode', 'electrons')].get_timeseries_by_key("J",
                                                                 False)[1:])

    # convert to cm^2
    J /= -1.0e4

    assert np.allclose(J_pickle, J, rtol=0.01, atol=0)

    # check that plotfile exists
    assert os.path.isfile("diags/fluxes/flux_plots_{:010d}.png".format(100))
Exemplo n.º 10
0
def test_flux_diag_accuracy(caplog):
    caplog.set_level(logging.INFO)
    name = "FluxDiagRun"
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed. For initial
    # statistics, instead use a plain random seed (commented out here).
    np.random.seed(18672033)

    # these values come from the default values in the mewarp diode setup
    TOTAL_TIME = 3e-10  # s
    DIAG_INTERVAL = 1e-10  # s
    DT = 1e-12  # s not from mewarp diode setup
    CATHODE_TEMP = 1550  # K
    ANODE_TEMP = 773  # K

    P_INERT = 4  # torr
    T_INERT = .5 * (CATHODE_TEMP + ANODE_TEMP)  # K
    NPPC = 2
    D_CA = 1.0e-4

    CATHODE_PHI = 2.4  # work function in eV
    NX = 8  # not from mewarp diode setup
    NZ = 128  # not from mewarp diode setup

    DIRECT_SOLVER = True

    max_steps = int(TOTAL_TIME / DT)
    diag_steps = int(DIAG_INTERVAL / DT)

    # Run with relatively large bias to have stronger signals.
    run = diode_setup.DiodeRun_V1(GEOM_STR='XZ',
                                  CATHODE_TEMP=CATHODE_TEMP,
                                  CATHODE_PHI=CATHODE_PHI,
                                  V_ANODE_CATHODE=20.,
                                  D_CA=D_CA,
                                  P_INERT=P_INERT,
                                  T_INERT=T_INERT,
                                  NPPC=NPPC,
                                  NX=NX,
                                  NZ=NZ,
                                  DIRECT_SOLVER=DIRECT_SOLVER,
                                  DT=DT,
                                  TOTAL_TIMESTEPS=max_steps,
                                  DIAG_STEPS=diag_steps,
                                  DIAG_INTERVAL=DIAG_INTERVAL,
                                  CHECK_CHARGE_CONSERVATION=False)

    run.setup_run(init_mcc=True, init_runinfo=True)
    run.fluxdiag = flux_diagnostic.FluxDiagnostic(
        diag_steps=run.DIAG_STEPS,
        runinfo=run.runinfo,
        check_charge_conservation=run.CHECK_CHARGE_CONSERVATION,
        overwrite=False,
        save_csv=True)
    run.init_warpx()

    mwxrun.simulation.step(max_steps)

    all_log_output = ""
    records = caplog.records

    for record in records:
        all_log_output += record.msg + "\n"

    # Check expected print output
    # Match a pattern to allow for numbers to change
    pattern = (r"""Cathode Electrons Current Emitted: -4\.5\d* A/cm\^2
Cathode Electrons Current Collected: 2\.[0-3]\d* A/cm\^2
Cathode Electrons Current Net: -2\.[234]\d* A/cm\^2
Cathode Ar_Ions Current Collected: 0 A/cm\^2
Anode Electrons Current Collected: 2\.[123]\d* A/cm\^2
Anode Ar_Ions Current Collected: 0 A/cm\^2
mcc Electrons Current Emitted: -0\.0\d* A/cm\^2
mcc Ar_Ions Current Emitted: 0\.0\d* A/cm\^2
Total Current Emitted: -4\.5\d* A/cm\^2
Total Current Collected: 4\.[3-8]\d* A/cm\^2
Total Current Net: -?0\.[01]\d* A/cm\^2
Total Power Net: -4[0-7]\.\d* W/cm\^2 """).replace("\n", " ")

    match = re.search(pattern, all_log_output.replace("\n", " "))

    assert match is not None

    print("Diagnostic output match:")
    print(match.group(0))

    #Check diagnostic files are present
    filelist = [
        'diags/fluxes/Anode_scraped.csv',
        'diags/fluxes/Cathode_scraped.csv',
        'diags/fluxes/flux_plots_0000000100.png',
        'diags/fluxes/flux_plots_0000000200.png',
        'diags/fluxes/flux_plots_0000000300.png',
        'diags/fluxes/fluxdata_0000000100.dpkl',
        'diags/fluxes/fluxdata_0000000200.dpkl',
        'diags/fluxes/fluxdata_0000000300.dpkl',
        'diags/fluxes/mcc_electrons_ar_ions_injected.csv',
        'diags/fluxes/thermionic_injector_electrons_injected.csv',
    ]

    for filename in filelist:
        assert os.path.isfile(filename)

    # Check that Qs plus powers sum to about 0 for most recent period
    Q_emit = run.fluxdiag.ts_dict[('inject', 'cathode',
                                   'electrons')].get_averagevalue_by_key('dQ')
    Q_abs_cathode = run.fluxdiag.ts_dict[(
        'scrape', 'cathode', 'electrons')].get_averagevalue_by_key('dQ')
    Q_abs_anode = run.fluxdiag.ts_dict[(
        'scrape', 'anode', 'electrons')].get_averagevalue_by_key('dQ')
    P_anode = run.fluxdiag.ts_dict[('scrape', 'anode',
                                    'electrons')].get_averagevalue_by_key('P')
    conservation = Q_emit + Q_abs_cathode + Q_abs_anode - P_anode
    print(f"Q_emit: {Q_emit} W/cm^2")
    print(f"Q_abs_cathode: {Q_abs_cathode} W/cm^2")
    print(f"Q_abs_anode: {Q_abs_anode} W/cm^2")
    print(f"P_anode: {P_anode} W/cm^2")
    print(f"Conservation: {conservation} W/cm^2")
    assert abs(conservation) < 0.4

    # Gather results to check.  The index call here ensures there's one row to
    # assign into in the new DataFrame.

    df = pandas.DataFrame(index=list(range(1)))

    for fluxtype in ['J', 'P', 'dQ', 'n']:
        df['inject_cathode_' + fluxtype] = run.fluxdiag.fullhist_dict[(
            'inject', 'cathode',
            'electrons')].get_averagevalue_by_key(fluxtype)
        df['scrape_cathode_' + fluxtype] = run.fluxdiag.fullhist_dict[(
            'scrape', 'cathode',
            'electrons')].get_averagevalue_by_key(fluxtype)
        df['scrape_anode_' + fluxtype] = run.fluxdiag.fullhist_dict[(
            'scrape', 'anode', 'electrons')].get_averagevalue_by_key(fluxtype)
        df['mcc_' + fluxtype] = run.fluxdiag.fullhist_dict[(
            'inject', 'mcc', 'electrons')].get_averagevalue_by_key(fluxtype)

    assert testing_util.test_df_vs_ref(name, df)

    # Check that loaded results are identical
    fluxdiag_2 = flux_diagnostic.FluxDiagFromFile()

    for key in run.fluxdiag.fullhist_dict:
        for fluxtype in ['J', 'P', 'dQ', 'n']:
            assert np.isclose(
                run.fluxdiag.fullhist_dict[key].get_averagevalue_by_key(
                    fluxtype),
                fluxdiag_2.fullhist_dict[key].get_averagevalue_by_key(
                    fluxtype))

            assert np.isclose(
                run.fluxdiag.ts_dict[key].get_averagevalue_by_key(fluxtype),
                fluxdiag_2.ts_dict[key].get_averagevalue_by_key(fluxtype))

    reftext = fluxdiag_2.print_fluxes(fluxdiag_2.ts_dict)
    print(reftext)

    match = re.search(pattern, reftext.replace("\n", " "))

    assert match is not None

    print("Postprocess output match:")
    print(match.group(0))
Exemplo n.º 11
0
def test_capacitive_discharge_multigrid(caplog, name):
    caplog.set_level(logging.INFO)
    # Include a random run number to allow parallel runs to not collide. Using
    # python randint prevents collisions due to numpy rseed below
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(92160881)

    GEOM_STR = name.split('_')[-1]

    # Specific numbers match older run for consistency
    FREQ = 13.56e6  # MHz
    DT = 1.0 / (400 * FREQ)
    DIAG_STEPS = 2
    DIAG_INTERVAL = DIAG_STEPS * DT
    VOLTAGE = 450.0
    D_CA = 0.067  # m
    run = diode_setup.DiodeRun_V1(
        GEOM_STR=GEOM_STR,
        V_ANODE_CATHODE=VOLTAGE,
        V_ANODE_EXPRESSION="%.1f*sin(2*pi*%.5e*t)" % (VOLTAGE, FREQ),
        D_CA=D_CA,
        INERT_GAS_TYPE='He',
        N_INERT=9.64e20,  # m^-3
        T_INERT=300.0,  # K
        PLASMA_DENSITY=2.56e14,  # m^-3
        T_ELEC=30000.0,  # K
        SEED_NPPC=16 * 32,
        NX=16,
        NZ=128,
        DT=DT,
        TOTAL_TIMESTEPS=10,
        DIAG_STEPS=DIAG_STEPS,
        DIAG_INTERVAL=DIAG_INTERVAL)
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=False,
                  init_injectors=False,
                  init_neutral_plasma=True,
                  init_mcc=True,
                  init_field_diag=True,
                  init_simcontrol=True,
                  init_warpx=True)

    # Run the main WARP loop
    while run.control.check_criteria():
        mwxrun.simulation.step()

    #######################################################################
    # Cleanup and final output                                            #
    #######################################################################

    all_log_output = ""
    records = caplog.records

    for record in records:
        all_log_output += record.msg + "\n"

    print(all_log_output)
    # make sure out isn't empty
    outstr = "SimControl: Termination from criteria: eval_total_steps"
    assert outstr in all_log_output
Exemplo n.º 12
0
def test_embedded_rectangle():
    name = "Embedded_rectangle_solve"
    # Include a random run number to allow parallel runs to not collide. Using
    # python randint prevents collisions due to numpy rseed below
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(92160881)

    # Specific numbers match older run for consistency
    D_CA = 1  # m
    run = diode_setup.DiodeRun_V1(
        GEOM_STR='XZ',
        D_CA=D_CA,
        NX=64,
        NZ=64,
        DT=1e-6,
        TOTAL_TIMESTEPS=1,
        DIAG_STEPS=1,
        FIELD_DIAG_DATA_LIST=['phi'],
    )
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=False,
                  init_scraper=False,
                  init_electrons=False,
                  init_solver=False,
                  init_injectors=False,
                  init_field_diag=True,
                  init_simcontrol=True,
                  init_simulation=False)

    # Install the embedded boundary
    cylinder = assemblies.Rectangle(center_x=0.0,
                                    center_z=0.5,
                                    length_x=0.3,
                                    length_z=0.3,
                                    V=-2.0,
                                    T=300,
                                    WF=4.7,
                                    name="Box")

    # Initialize solver
    run.init_solver()
    run.init_conductors()

    # Initialize the simulation
    run.init_simulation()
    run.init_warpx()

    # Run the main WARP loop
    while run.control.check_criteria():
        mwxrun.simulation.step()

    #######################################################################
    # Check phi results against reference data                            #
    #######################################################################

    phi = mwxrun.get_gathered_phi_grid(include_ghosts=False)
    # np.save('embedded_rectangle_phi.npy', phi)
    ref_phi = np.load(
        os.path.join(testing_util.test_dir, 'embedded_boundary',
                     'embedded_rectangle_phi.npy'))

    assert np.allclose(phi, ref_phi, rtol=0.001)
Exemplo n.º 13
0
def test_two_embedded_cylinders_scraping():
    name = "two_embedded_cylinders_scraping"
    # Include a random run number to allow parallel runs to not collide. Using
    # python randint prevents collisions due to numpy rseed below
    testing_util.initialize_testingdir(name)

    # Initialize each run with consistent, randomly-chosen, rseed. Use a random
    # seed instead for initial dataframe generation.
    # np.random.seed()
    np.random.seed(42147820)

    # Specific numbers match older run for consistency
    D_CA = 0.025  # m
    run = diode_setup.DiodeRun_V1(
        GEOM_STR='XZ',
        #V_ANODE_CATHODE=VOLTAGE,
        D_CA=D_CA,
        NX=64,
        NZ=64,
        DT=1e-10,
        TOTAL_TIMESTEPS=15,
        DIAG_STEPS=15,
        FIELD_DIAG_DATA_LIST=['phi'],
        # FIELD_DIAG_PLOT=True,
        INERT_GAS_TYPE='positron')
    # Only the functions we change from defaults are listed here
    run.setup_run(init_conductors=False,
                  init_scraper=False,
                  init_electrons=True,
                  init_inert_gas=True,
                  init_solver=False,
                  init_injectors=False,
                  init_field_diag=True,
                  init_simcontrol=True,
                  init_simulation=False)

    # Install the embedded boundaries
    cylinder1 = assemblies.InfCylinderY(center_x=-0.25 * D_CA,
                                        center_z=0.5 * D_CA,
                                        radius=0.1 * D_CA,
                                        V=-0.5,
                                        T=300,
                                        WF=4.7,
                                        name="Cylinder1")
    cylinder2 = assemblies.InfCylinderY(center_x=0.25 * D_CA,
                                        center_z=0.5 * D_CA,
                                        radius=0.1 * D_CA,
                                        V=0.2,
                                        T=300,
                                        WF=4.7,
                                        name="Cylinder2")

    # Initialize solver
    run.init_solver()
    run.init_conductors()
    run.electrons.save_particles_at_eb = 1
    run.ions.save_particles_at_eb = 1

    # Inject particles in the simulation
    volemitter = emission.ZSinDistributionVolumeEmitter(
        T=3000,
        zmin=0,
        zmax=run.D_CA,
    )
    emission.PlasmaInjector(
        emitter=volemitter,
        species1=run.electrons,
        species2=run.ions,
        npart=4000,
        plasma_density=1e14,
    )

    # Initialize the simulation
    run.init_simulation()
    run.init_warpx()

    # Run the main WARP loop
    while run.control.check_criteria():
        mwxrun.simulation.step()

    #######################################################################
    # Check flux on each cylinder                                         #
    #######################################################################

    cylinder1.init_scrapedparticles(cylinder1.fields)
    cylinder1.record_scrapedparticles()
    cyl1_scraped = cylinder1.get_scrapedparticles()

    cylinder2.init_scrapedparticles(cylinder2.fields)
    cylinder2.record_scrapedparticles()
    cyl2_scraped = cylinder2.get_scrapedparticles()

    assert np.allclose(cyl1_scraped['n'], np.array([2, 0]))
    assert np.allclose(cyl2_scraped['n'], np.array([1, 2]))

    #######################################################################
    # Check rho results against reference data                            #
    #######################################################################

    rho = mwxrun.get_gathered_rho_grid(include_ghosts=False)[:, :, 0]
    # np.save('two_embedded_cylinders_rho.npy', rho)
    ref_rho = np.load(
        os.path.join(testing_util.test_dir, 'embedded_boundary',
                     'two_embedded_cylinders_rho.npy'))
    assert np.allclose(rho, ref_rho)