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
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)
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}"
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)
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)
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!")
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))
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))
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
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)
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)