Skip to content

Commit 3a1d391

Browse files
committed
Update laser-ion acc example
- add PICMI input - add vis script - update docs - add Python regression test - update phase space analysis script - add checksum regression test
1 parent 920b3e8 commit 3a1d391

File tree

8 files changed

+687
-42
lines changed

8 files changed

+687
-42
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
#!/usr/bin/env python3
2+
3+
from pywarpx import picmi
4+
5+
# Physical constants
6+
c = picmi.constants.c
7+
q_e = picmi.constants.q_e
8+
9+
# We only run 100 steps for tests
10+
# Disable `max_step` below to run until the physical `stop_time`.
11+
max_step = 100
12+
# time-scale with highly kinetic dynamics
13+
stop_time = 0.2e-12
14+
15+
# proper resolution for 30 n_c (dx<=3.33nm) incl. acc. length
16+
# (>=6x V100)
17+
# --> choose larger `max_grid_size` and `blocking_factor` for 1 to 8 grids per GPU accordingly
18+
#nx = 7488
19+
#nz = 14720
20+
21+
# Number of cells
22+
nx = 384
23+
nz = 512
24+
25+
# Domain decomposition (deactivate `warpx_numprocs` in `picmi.Simulation` for this to take effect)
26+
max_grid_size = 64
27+
blocking_factor = 32
28+
29+
# Physical domain
30+
xmin = -7.5e-06
31+
xmax = 7.5e-06
32+
zmin = -5.0e-06
33+
zmax = 25.0e-06
34+
35+
# Create grid
36+
grid = picmi.Cartesian2DGrid(
37+
number_of_cells=[nx, nz],
38+
lower_bound=[xmin, zmin],
39+
upper_bound=[xmax, zmax],
40+
lower_boundary_conditions=['open', 'open'],
41+
upper_boundary_conditions=['open', 'open'],
42+
lower_boundary_conditions_particles=['absorbing', 'absorbing'],
43+
upper_boundary_conditions_particles=['absorbing', 'absorbing'],
44+
warpx_max_grid_size=max_grid_size,
45+
warpx_blocking_factor=blocking_factor)
46+
47+
# Particles: plasma parameters
48+
# critical plasma density
49+
nc = 1.742e27 # [m^-3] 1.11485e21 * 1.e6 / 0.8**2
50+
# number density: "fully ionized" electron density as reference
51+
# [material 1] cryogenic H2
52+
n0 = 30.0 # [n_c]
53+
# [material 2] liquid crystal
54+
# n0 = 192
55+
# [material 3] PMMA
56+
# n0 = 230
57+
# [material 4] Copper (ion density: 8.49e28/m^3; times ionization level)
58+
# n0 = 1400
59+
plasma_density = n0 * nc
60+
preplasma_L = 0.05e-6 # [m] scale length (>0)
61+
preplasma_Lcut = 2.0e-6 # [m] hard cutoff from surface
62+
plasma_r0 = 2.5e-6 # [m] radius or half-thickness
63+
plasma_eps_z = 0.05e-6 # [m] small offset in z to make zmin, zmax interval larger than 2*(r0 + Lcut)
64+
plasma_creation_limit_z = plasma_r0 + preplasma_Lcut + plasma_eps_z # [m] upper limit in z for particle creation
65+
66+
plasma_xmin = None
67+
plasma_ymin = None
68+
plasma_zmin = -plasma_creation_limit_z
69+
plasma_xmax = None
70+
plasma_ymax = None
71+
plasma_zmax = plasma_creation_limit_z
72+
73+
density_expression_str = f'{plasma_density}*((abs(z)<={plasma_r0}) + (abs(z)<{plasma_r0}+{preplasma_Lcut}) * (abs(z)>{plasma_r0}) * exp(-(abs(z)-{plasma_r0})/{preplasma_L}))'
74+
75+
slab_with_ramp_dist_hydrogen = picmi.AnalyticDistribution(
76+
density_expression=density_expression_str,
77+
lower_bound=[plasma_xmin, plasma_ymin, plasma_zmin],
78+
upper_bound=[plasma_xmax, plasma_ymax, plasma_zmax]
79+
)
80+
81+
# thermal velocity spread for electrons in gamma*beta
82+
ux_th = .01
83+
uz_th = .01
84+
85+
slab_with_ramp_dist_electrons = picmi.AnalyticDistribution(
86+
density_expression=density_expression_str,
87+
lower_bound=[plasma_xmin, plasma_ymin, plasma_zmin],
88+
upper_bound=[plasma_xmax, plasma_ymax, plasma_zmax],
89+
# if `momentum_expressions` and `momentum_spread_expressions` are unset,
90+
# a Gaussian momentum distribution is assumed given that `rms_velocity` has any non-zero elements
91+
rms_velocity=[c*ux_th, 0., c*uz_th] # thermal velocity spread in m/s
92+
)
93+
94+
# TODO: add additional attributes orig_x and orig_z
95+
electrons = picmi.Species(
96+
particle_type='electron',
97+
name='electrons',
98+
initial_distribution=slab_with_ramp_dist_electrons,
99+
)
100+
101+
# TODO: add additional attributes orig_x and orig_z
102+
hydrogen = picmi.Species(
103+
particle_type='proton',
104+
name='hydrogen',
105+
initial_distribution=slab_with_ramp_dist_hydrogen
106+
)
107+
108+
# Laser
109+
# e_max = a0 * 3.211e12 / lambda_0[mu]
110+
# a0 = 16, lambda_0 = 0.8mu -> e_max = 64.22 TV/m
111+
e_max = 64.22e12
112+
position_z = -4.0e-06
113+
profile_t_peak = 50.e-15
114+
profile_focal_distance = 4.0e-06
115+
laser = picmi.GaussianLaser(
116+
wavelength=0.8e-06,
117+
waist=4.e-06,
118+
duration=30.e-15,
119+
focal_position=[0, 0, profile_focal_distance + position_z],
120+
centroid_position=[0, 0, position_z - c * profile_t_peak],
121+
propagation_direction=[0, 0, 1],
122+
polarization_direction=[1, 0, 0],
123+
E0=e_max,
124+
fill_in=False)
125+
laser_antenna = picmi.LaserAntenna(
126+
position=[0., 0., position_z],
127+
normal_vector=[0, 0, 1])
128+
129+
# Electromagnetic solver
130+
solver = picmi.ElectromagneticSolver(
131+
grid=grid,
132+
method='Yee',
133+
cfl=0.999,
134+
divE_cleaning=0,
135+
#warpx_pml_ncell=10
136+
)
137+
138+
# Diagnostics
139+
diag_field_list = ['B', 'E', 'J', 'rho', 'rho_electrons', 'rho_hydrogen']
140+
particle_diag = picmi.ParticleDiagnostic(
141+
name='diag1',
142+
period=100,
143+
write_dir='./diags',
144+
species=[electrons],
145+
data_list=['weighting', 'position', 'momentum'],
146+
warpx_format='openpmd',
147+
warpx_openpmd_backend='bp',
148+
# >500keV for electrons (first term is m*c*c/q_e)
149+
warpx_plot_filter_function='(x<1.0e-6) * (x>-1.0e-6) * (5.1100e+05*(sqrt(1.0+ux*ux+uy*uy+uz*uz)-1.0)>500.0e3)'
150+
)
151+
# reduce resolution of output fields
152+
coarsening_ratio = [4, 4]
153+
ncell_field = []
154+
for (ncell_comp, cr) in zip([nx,nz], coarsening_ratio):
155+
ncell_field.append(int(ncell_comp/cr))
156+
field_diag = picmi.FieldDiagnostic(
157+
name='diag1',
158+
grid=grid,
159+
period=100,
160+
number_of_cells=ncell_field,
161+
data_list=diag_field_list,
162+
write_dir='./diags',
163+
warpx_format='openpmd',
164+
warpx_openpmd_backend='bp'
165+
)
166+
167+
particle_fw_diag = picmi.ParticleDiagnostic(
168+
name='openPMDfw',
169+
period=100,
170+
write_dir='./diags',
171+
species=[hydrogen],
172+
data_list=['weighting', 'position', 'momentum'],
173+
warpx_format='openpmd',
174+
warpx_openpmd_backend='h5',
175+
warpx_plot_filter_function='(uz>=0) * (x<1.0e-6) * (x>-1.0e-6)'
176+
)
177+
178+
particle_bw_diag = picmi.ParticleDiagnostic(
179+
name='openPMDbw',
180+
period=100,
181+
write_dir='./diags',
182+
species=[hydrogen, electrons],
183+
data_list=['weighting', 'position', 'momentum'],
184+
warpx_format='openpmd',
185+
warpx_openpmd_backend='h5',
186+
warpx_plot_filter_function='(uz<0)'
187+
)
188+
189+
# histograms with 2.0 degree acceptance angle in fw direction
190+
# 2 deg * pi / 180 : 0.03490658503 rad
191+
# half-angle +/- : 0.017453292515 rad
192+
histuH_rdiag = picmi.ReducedDiagnostic(
193+
diag_type='ParticleHistogram',
194+
name='histuH',
195+
period=100,
196+
species=hydrogen,
197+
bin_number=1000,
198+
bin_min=0.0,
199+
bin_max=0.474, # 100 MeV protons
200+
histogram_function='u2=ux*ux+uy*uy+uz*uz; if(u2>0, sqrt(u2), 0.0)',
201+
filter_function='u2=ux*ux+uy*uy+uz*uz; if(u2>0, abs(acos(uz / sqrt(u2))) <= 0.017453, 0)')
202+
203+
histue_rdiag = picmi.ReducedDiagnostic(
204+
diag_type='ParticleHistogram',
205+
name='histue',
206+
period=100,
207+
species=electrons,
208+
bin_number=1000,
209+
bin_min=0.0,
210+
bin_max=197.0, # 100 MeV electrons
211+
histogram_function='u2=ux*ux+uy*uy+uz*uz; if(u2>0, sqrt(u2), 0.0)',
212+
filter_function='u2=ux*ux+uy*uy+uz*uz; if(u2>0, abs(acos(uz / sqrt(u2))) <= 0.017453, 0)')
213+
214+
# just a test entry to make sure that the histogram filter is purely optional:
215+
# this one just records uz of all hydrogen ions, independent of their pointing
216+
histuzAll_rdiag = picmi.ReducedDiagnostic(
217+
diag_type='ParticleHistogram',
218+
name='histuzAll',
219+
period=100,
220+
species=hydrogen,
221+
bin_number=1000,
222+
bin_min=-0.474,
223+
bin_max=0.474,
224+
histogram_function='uz')
225+
226+
field_probe_z_rdiag = picmi.ReducedDiagnostic(
227+
diag_type='FieldProbe',
228+
name='FieldProbe_Z',
229+
period=100,
230+
integrate=0,
231+
probe_geometry='Line',
232+
x_probe=0.0,
233+
z_probe=-5.0e-6,
234+
x1_probe=0.0,
235+
z1_probe=25.0e-6,
236+
resolution=3712)
237+
238+
field_probe_scat_point_rdiag = picmi.ReducedDiagnostic(
239+
diag_type='FieldProbe',
240+
name='FieldProbe_ScatPoint',
241+
period=1,
242+
integrate=0,
243+
probe_geometry='Point',
244+
x_probe=0.0,
245+
z_probe=15.0e-6)
246+
247+
field_probe_scat_line_rdiag = picmi.ReducedDiagnostic(
248+
diag_type='FieldProbe',
249+
name='FieldProbe_ScatLine',
250+
period=100,
251+
integrate=1,
252+
probe_geometry='Line',
253+
x_probe=-2.5e-6,
254+
z_probe=15.0e-6,
255+
x1_probe=2.5e-6,
256+
z1_probe=15e-6,
257+
resolution=201)
258+
259+
load_balance_costs_rdiag = picmi.ReducedDiagnostic(
260+
diag_type='LoadBalanceCosts',
261+
name='LBC',
262+
period=100)
263+
264+
# Set up simulation
265+
sim = picmi.Simulation(
266+
solver=solver,
267+
max_time=stop_time, # need to remove `max_step` to run this far
268+
verbose=1,
269+
particle_shape='cubic',
270+
warpx_numprocs=[1, 2], # deactivate `numprocs` for dynamic load balancing
271+
warpx_use_filter=1,
272+
warpx_load_balance_intervals=100,
273+
warpx_load_balance_costs_update='heuristic'
274+
)
275+
276+
# Add plasma electrons
277+
sim.add_species(
278+
electrons,
279+
layout=picmi.GriddedLayout(grid=grid, n_macroparticle_per_cell=[2,2])
280+
# for more realistic simulations, try to avoid that macro-particles represent more than 1 n_c
281+
#layout=picmi.GriddedLayout(grid=grid, n_macroparticle_per_cell=[4,8])
282+
)
283+
284+
# Add hydrogen ions
285+
sim.add_species(
286+
hydrogen,
287+
layout=picmi.GriddedLayout(grid=grid, n_macroparticle_per_cell=[2,2])
288+
# for more realistic simulations, try to avoid that macro-particles represent more than 1 n_c
289+
#layout=picmi.GriddedLayout(grid=grid, n_macroparticle_per_cell=[4,8])
290+
)
291+
292+
# Add laser
293+
sim.add_laser(
294+
laser,
295+
injection_method=laser_antenna)
296+
297+
# Add full diagnostics
298+
sim.add_diagnostic(particle_diag)
299+
sim.add_diagnostic(field_diag)
300+
sim.add_diagnostic(particle_fw_diag)
301+
sim.add_diagnostic(particle_bw_diag)
302+
# Add reduced diagnostics
303+
sim.add_diagnostic(histuH_rdiag)
304+
sim.add_diagnostic(histue_rdiag)
305+
sim.add_diagnostic(histuzAll_rdiag)
306+
sim.add_diagnostic(field_probe_z_rdiag)
307+
sim.add_diagnostic(field_probe_scat_point_rdiag)
308+
sim.add_diagnostic(field_probe_scat_line_rdiag)
309+
sim.add_diagnostic(load_balance_costs_rdiag)
310+
# TODO: make ParticleHistogram2D available
311+
312+
# Write input file that can be used to run with the compiled version
313+
sim.write_input_file(file_name='inputs_2d_picmi')
314+
315+
# Initialize inputs and WarpX instance
316+
sim.initialize_inputs()
317+
sim.initialize_warpx()
318+
319+
# Advance simulation until last time step
320+
sim.step(max_step)

0 commit comments

Comments
 (0)