Skip to content

Commit eea86b6

Browse files
committed
Return to first-order pred-corr scheme
1 parent 1c3352d commit eea86b6

File tree

8 files changed

+150
-1716
lines changed

8 files changed

+150
-1716
lines changed

lcode2dPy/plasma3d/fields.py

+27-23
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ def dx_dy(arr, grid_step_size):
8383
return dx / (grid_step_size * 2), dy / (grid_step_size * 2)
8484

8585

86-
def calculate_Ex_Ey_Bx_By(grid_step_size, xi_step_size, trick, variant_A,
87-
const: Const_Arrays, fields_avg: Fields,
88-
beam_ro, currents: Currents, currents_prev: Currents):
86+
def calculate_Ex_Ey_Bx_By(
87+
grid_step_size, xi_step_size, trick, variant_A, const: Const_Arrays,
88+
fields_avg: Fields, ro_beam_full, ro_beam_prev, currents_full: Currents,
89+
currents_prev: Currents
90+
):
8991
"""
9092
Calculate transverse fields as iDST-DCT(mixed_matrix * DST-DCT(RHS.T)).T,
9193
with and without transposition depending on the field component.
@@ -95,14 +97,16 @@ def calculate_Ex_Ey_Bx_By(grid_step_size, xi_step_size, trick, variant_A,
9597
minus the coarse plasma particle cloud width).
9698
"""
9799
jx_prev, jy_prev = currents_prev.jx, currents_prev.jy
98-
jx, jy = currents.jx, currents.jy
100+
jx, jy = currents_full.jx, currents_full.jy
99101

100-
ro = currents.ro if not variant_A else (currents.ro + currents_prev.ro) / 2
101-
jz = currents.jz if not variant_A else (currents.jz + currents_prev.jz) / 2
102+
ro = (currents_full.ro + ro_beam_full +
103+
currents_prev.ro + ro_beam_prev) / 2
104+
jz = (currents_full.jz + ro_beam_full +
105+
currents_prev.jz + ro_beam_prev) / 2
102106

103107
# 1. Calculate gradients and RHS.
104-
dro_dx, dro_dy = dx_dy(ro + beam_ro, grid_step_size)
105-
djz_dx, djz_dy = dx_dy(jz + beam_ro, grid_step_size)
108+
dro_dx, dro_dy = dx_dy(ro, grid_step_size)
109+
djz_dx, djz_dy = dx_dy(jz, grid_step_size)
106110
djx_dxi = (jx_prev - jx) / xi_step_size # - ?
107111
djy_dxi = (jy_prev - jy) / xi_step_size # - ?
108112

@@ -191,29 +195,29 @@ def __init__(self, config: Config):
191195
self.trick = config.getfloat('field-solver-subtraction-trick')
192196
self.variant_A = config.getbool('field-solver-variant-A')
193197

194-
def compute_fields(self, flds: Fields, flds_prev: Fields,
195-
const: Const_Arrays, rho_beam,
196-
curr_prev: Currents, curr: Currents):
198+
def compute_fields(
199+
self, fields: Fields, flds_prev: Fields, const: Const_Arrays,
200+
rho_beam_full, rho_beam_prev, currents_prev: Currents,
201+
currents_full: Currents
202+
):
197203
# Looks terrible! TODO: rewrite this function entirely
198-
new_flds = Fields((flds.Ex).shape[0])
204+
new_flds = Fields((fields.Ex).shape[0])
199205

200-
(new_flds.Ex,
201-
new_flds.Ey,
202-
new_flds.Bx,
203-
new_flds.By) = calculate_Ex_Ey_Bx_By(self.grid_step_size,
204-
self.xi_step_size,
205-
self.trick, self.variant_A, const,
206-
flds, rho_beam, curr, curr_prev)
206+
new_flds.Ex, new_flds.Ey, new_flds.Bx, new_flds.By =\
207+
calculate_Ex_Ey_Bx_By(
208+
self.grid_step_size, self.xi_step_size, self.trick,
209+
self.variant_A, const, fields, rho_beam_full, rho_beam_prev,
210+
currents_full, currents_prev
211+
)
207212

208213
if self.variant_A:
209214
new_flds.Ex = 2 * new_flds.Ex - flds_prev.Ex
210215
new_flds.Ey = 2 * new_flds.Ey - flds_prev.Ey
211216
new_flds.Bx = 2 * new_flds.Bx - flds_prev.Bx
212217
new_flds.By = 2 * new_flds.By - flds_prev.By
213218

214-
new_flds.Ez = calculate_Ez(self.grid_step_size, const, curr)
215-
new_flds.Bz = calculate_Bz(self.grid_step_size, const, curr)
216-
217-
new_flds.Phi = calculate_Phi(const, curr)
219+
new_flds.Ez = calculate_Ez(self.grid_step_size, const, currents_full)
220+
new_flds.Bz = calculate_Bz(self.grid_step_size, const, currents_full)
221+
new_flds.Phi = calculate_Phi(const, currents_full)
218222

219223
return new_flds, new_flds.average(flds_prev)

lcode2dPy/plasma3d/solver.py

+47-28
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,50 @@ def __init__(self, config: Config):
1111
self.PMover = ParticleMover(config)
1212
self.CComputer = RhoJComputer(config)
1313

14-
# Perfoms one full step along xi
15-
def step_dxi(self, particles_prev: Particles, fields_prev: Fields,
16-
currents_prev: Currents, const_arrays: Const_Arrays, rho_beam):
17-
particles = self.PMover.move_particles_wo_fields(particles_prev)
18-
19-
20-
particles = self.PMover.move_particles(fields_prev,
21-
particles_prev, particles)
22-
currents = self.CComputer.compute_rhoj(particles, const_arrays)
23-
24-
_, fields_avg = self.FComputer.compute_fields(fields_prev, fields_prev,
25-
const_arrays, rho_beam,
26-
currents_prev, currents)
27-
28-
29-
particles = self.PMover.move_particles(fields_avg,
30-
particles_prev, particles)
31-
currents = self.CComputer.compute_rhoj(particles, const_arrays)
32-
33-
fields, fields_avg = self.FComputer.compute_fields(fields_avg, fields_prev,
34-
const_arrays, rho_beam,
35-
currents_prev, currents)
36-
37-
particles = self.PMover.move_particles(fields_avg,
38-
particles_prev, particles)
39-
currents = self.CComputer.compute_rhoj(particles, const_arrays)
40-
41-
return particles, fields, currents
14+
# Perfoms one full step along xi.
15+
# To understand the numerical scheme, read values as following:
16+
# *_prev = * on the previous xi step, an index number = k
17+
# *_half = * on the halfstep, an index number = k + 1/2
18+
# *_full = * on the next xi step (fullstep), an index number = k + 1
19+
# *_prevprev = * on the xi step with an index number k - 1
20+
def step_dxi(
21+
self, particles_prev: Particles, fields_prev: Fields,
22+
currents_prev: Currents, const_arrays: Const_Arrays,
23+
rho_beam_full, rho_beam_prev
24+
):
25+
particles_full = self.PMover.move_particles_wo_fields(particles_prev)
26+
27+
28+
particles_full = self.PMover.move_particles(
29+
fields_prev, particles_prev, particles_full
30+
)
31+
currents_full = self.CComputer.compute_rhoj(
32+
particles_full, const_arrays
33+
)
34+
35+
_, fields_half = self.FComputer.compute_fields(
36+
fields_prev, fields_prev, const_arrays, rho_beam_full, rho_beam_prev,
37+
currents_prev, currents_full
38+
)
39+
40+
41+
particles_full = self.PMover.move_particles(
42+
fields_half, particles_prev, particles_full
43+
)
44+
currents_full = self.CComputer.compute_rhoj(
45+
particles_full, const_arrays
46+
)
47+
48+
fields_full, fields_half = self.FComputer.compute_fields(
49+
fields_half, fields_prev, const_arrays, rho_beam_full, rho_beam_prev,
50+
currents_prev, currents_full
51+
)
52+
53+
particles_full = self.PMover.move_particles(
54+
fields_half, particles_prev, particles_full
55+
)
56+
currents_full = self.CComputer.compute_rhoj(
57+
particles_full, const_arrays
58+
)
59+
60+
return particles_full, fields_full, currents_full

lcode2dPy/plasma3d_gpu/fields.py

+20-96
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ def dx_dy(arr, grid_step_size):
111111
return dx / (grid_step_size * 2), dy / (grid_step_size * 2)
112112

113113

114-
def calculate_Ex_Ey_Bx_By_predictor(
115-
grid_step_size, xi_step_size, const, fields_prev, ro_beam_full, ro_beam_prev,
114+
def calculate_Ex_Ey_Bx_By(
115+
grid_step_size, xi_step_size, const, fields, ro_beam_full, ro_beam_prev,
116116
currents_full, currents_prev
117117
):
118118
"""
@@ -138,10 +138,10 @@ def calculate_Ex_Ey_Bx_By_predictor(
138138
djy_dxi = (jy_prev - jy_full) / xi_step_size # - ?
139139

140140
# We are solving a Helmholtz equation
141-
Ex_rhs = -(dro_dx - djx_dxi - fields_prev.Ex) # -?
142-
Ey_rhs = -(dro_dy - djy_dxi - fields_prev.Ey)
143-
Bx_rhs = +(djz_dy - djy_dxi + fields_prev.Bx)
144-
By_rhs = -(djz_dx - djx_dxi - fields_prev.By)
141+
Ex_rhs = -(dro_dx - djx_dxi - fields.Ex) # -?
142+
Ey_rhs = -(dro_dy - djy_dxi - fields.Ey)
143+
Bx_rhs = +(djz_dy - djy_dxi + fields.Bx)
144+
By_rhs = -(djz_dx - djx_dxi - fields.By)
145145

146146
# Boundary conditions application (for future reference, ours are zero):
147147
# rhs[:, 0] -= bound_bottom[:] * (2 / grid_step_size)
@@ -155,68 +155,14 @@ def calculate_Ex_Ey_Bx_By_predictor(
155155
Ey_f *= mix_mat
156156

157157
# 3. Apply our mixed DCT-DST transform again.
158-
Ey_half = mix2d(Ey_f)
158+
Ey = mix2d(Ey_f)
159159

160160
# Likewise for other fields:
161-
Bx_half = mix2d(mix_mat * mix2d(Bx_rhs[1:-1, :])[1:-1, :])
162-
By_half = mix2d(mix_mat * mix2d(By_rhs.T[1:-1, :])[1:-1, :]).T
163-
Ex_half = mix2d(mix_mat * mix2d(Ex_rhs.T[1:-1, :])[1:-1, :]).T
161+
Bx = mix2d(mix_mat * mix2d(Bx_rhs[1:-1, :])[1:-1, :])
162+
By = mix2d(mix_mat * mix2d(By_rhs.T[1:-1, :])[1:-1, :]).T
163+
Ex = mix2d(mix_mat * mix2d(Ex_rhs.T[1:-1, :])[1:-1, :]).T
164164

165-
return Ex_half, Ey_half, Bx_half, By_half
166-
167-
168-
def calculate_Ex_Ey_Bx_By_corrector(
169-
grid_step_size, xi_step_size, const, fields_full, ro_beam_full,
170-
currents_full, currents_prev, currents_prevprev
171-
):
172-
"""
173-
Calculate transverse fields as iDST-DCT(mixed_matrix * DST-DCT(RHS.T)).T,
174-
with and without transposition depending on the field component.
175-
NOTE: density and currents are assumed to be zero on the perimeter
176-
(no plasma particles must reach the wall, so the reflection boundary
177-
must be closer to the center than the simulation window boundary
178-
minus the coarse plasma particle cloud width).
179-
"""
180-
jx_prevprev, jy_prevprev = currents_prevprev.jx, currents_prevprev.jy
181-
jx_prev, jy_prev = currents_prev.jx, currents_prev.jy
182-
jx_full, jy_full = currents_full.jx, currents_full.jy
183-
184-
ro_full = currents_full.ro
185-
jz_full = currents_full.jz
186-
187-
# 0. Calculate gradients and RHS.
188-
dro_dx, dro_dy = dx_dy(ro_full + ro_beam_full, grid_step_size)
189-
djz_dx, djz_dy = dx_dy(jz_full + ro_beam_full, grid_step_size)
190-
191-
djx_dxi = (- jx_prevprev + 4 * jx_prev - 3 * jx_full) / (2 * xi_step_size)
192-
djy_dxi = (- jy_prevprev + 4 * jy_prev - 3 * jy_full) / (2 * xi_step_size)
193-
194-
# We are solving a Helmholtz equation
195-
Ex_rhs = -(dro_dx - djx_dxi - fields_full.Ex) # -?
196-
Ey_rhs = -(dro_dy - djy_dxi - fields_full.Ey)
197-
Bx_rhs = +(djz_dy - djy_dxi + fields_full.Bx)
198-
By_rhs = -(djz_dx - djx_dxi - fields_full.By)
199-
200-
# Boundary conditions application (for future reference, ours are zero):
201-
# rhs[:, 0] -= bound_bottom[:] * (2 / grid_step_size)
202-
# rhs[:, -1] += bound_top[:] * (2 / grid_step_size)
203-
204-
# 1. Apply our mixed DCT-DST transform to RHS.
205-
Ey_f = mix2d(Ey_rhs[1:-1, :])[1:-1, :]
206-
207-
# 2. Multiply f by the magic matrix.
208-
mix_mat = const.field_mixed_matrix
209-
Ey_f *= mix_mat
210-
211-
# 3. Apply our mixed DCT-DST transform again.
212-
Ey_full = mix2d(Ey_f)
213-
214-
# Likewise for other fields:
215-
Bx_full = mix2d(mix_mat * mix2d(Bx_rhs[1:-1, :])[1:-1, :])
216-
By_full = mix2d(mix_mat * mix2d(By_rhs.T[1:-1, :])[1:-1, :]).T
217-
Ex_full = mix2d(mix_mat * mix2d(Ex_rhs.T[1:-1, :])[1:-1, :]).T
218-
219-
return Ex_full, Ey_full, Bx_full, By_full
165+
return Ex, Ey, Bx, By
220166

221167

222168
# Pushing particles without any fields (used for initial halfstep estimation) #
@@ -297,25 +243,25 @@ def __init__(self, config: Config):
297243
self.trick = config.getfloat('field-solver-subtraction-trick')
298244
self.variant_A = config.getbool('field-solver-variant-A')
299245

300-
def compute_fields_predictor(
301-
self, fields_prev, const, rho_beam, rho_beam_prev, currents_prev,
302-
currents_full
246+
def compute_fields(
247+
self, fields, fields_prev, const, rho_beam_full, rho_beam_prev,
248+
currents_prev, currents_full
303249
):
304250
# Looks terrible! TODO: rewrite this function entirely
305251

306-
Ex_half, Ey_half, Bx_half, By_half = calculate_Ex_Ey_Bx_By_predictor(
307-
self.grid_step_size, self.xi_step_size, const, fields_prev,
308-
rho_beam, rho_beam_prev, currents_full, currents_prev
252+
Ex_half, Ey_half, Bx_half, By_half = calculate_Ex_Ey_Bx_By(
253+
self.grid_step_size, self.xi_step_size, const, fields,
254+
rho_beam_full, rho_beam_prev, currents_full, currents_prev
309255
)
310256

311257
Ex_full = 2 * Ex_half - fields_prev.Ex
312258
Ey_full = 2 * Ey_half - fields_prev.Ey
313259
Bx_full = 2 * Bx_half - fields_prev.Bx
314260
By_full = 2 * By_half - fields_prev.By
315261

316-
Ez_full = calculate_Ez(self.grid_step_size, const, currents_full)
317-
Bz_full = calculate_Bz(self.grid_step_size, const, currents_full)
318-
Phi = fields_prev.Phi #calculate_Phi(const, currents_full)
262+
Ez_full = calculate_Ez(self.grid_step_size, const, currents_full)
263+
Bz_full = calculate_Bz(self.grid_step_size, const, currents_full)
264+
Phi = calculate_Phi(const, currents_full)
319265

320266
fields_full = GPUArrays(
321267
Ex=Ex_full, Ey=Ey_full, Ez=Ez_full,
@@ -333,25 +279,3 @@ def compute_fields_predictor(
333279
)
334280

335281
return fields_full, fields_half
336-
337-
def compute_fields_corrector(
338-
self, fields_full, fields_prev, const, rho_beam, currents_prevprev,
339-
currents_prev, currents_full
340-
):
341-
342-
Ex_full, Ey_full, Bx_full, By_full = calculate_Ex_Ey_Bx_By_corrector(
343-
self.grid_step_size, self.xi_step_size, const, fields_full,
344-
rho_beam, currents_full, currents_prev, currents_prevprev
345-
)
346-
347-
Ez_full = calculate_Ez(self.grid_step_size, const, currents_full)
348-
Bz_full = calculate_Bz(self.grid_step_size, const, currents_full)
349-
Phi_full = calculate_Phi(const, currents_full)
350-
351-
fields_full = GPUArrays(
352-
Ex=Ex_full, Ey=Ey_full, Ez=Ez_full,
353-
Bx=Bx_full, By=By_full, Bz=Bz_full,
354-
Phi=Phi_full
355-
)
356-
357-
return fields_full, fields_average(fields_full, fields_prev)

lcode2dPy/plasma3d_gpu/solver.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ def __init__(self, config: Config):
1919
# *_prevprev = * on the xi step with an index number k - 1
2020
def step_dxi(
2121
self, particles_prev: GPUArrays, fields_prev: GPUArrays,
22-
currents_prev: GPUArrays, currents_prevprev: GPUArrays,
23-
const_arrays: GPUArrays, rho_beam, rho_beam_prev
22+
currents_prev: GPUArrays, const_arrays: GPUArrays,
23+
rho_beam_full, rho_beam_prev
2424
):
2525
particles_full = self.PMover.move_particles_wo_fields(particles_prev)
2626

@@ -32,9 +32,9 @@ def step_dxi(
3232
particles_full, const_arrays
3333
)
3434

35-
fields_full, fields_half= self.FComputer.compute_fields_predictor(
36-
fields_prev, const_arrays, rho_beam, rho_beam_prev, currents_prev,
37-
currents_full
35+
_, fields_half = self.FComputer.compute_fields(
36+
fields_prev, fields_prev, const_arrays, rho_beam_full, rho_beam_prev,
37+
currents_prev, currents_full
3838
)
3939

4040

@@ -45,8 +45,8 @@ def step_dxi(
4545
particles_full, const_arrays
4646
)
4747

48-
fields_full, fields_half = self.FComputer.compute_fields_corrector(
49-
fields_full, fields_prev, const_arrays, rho_beam, currents_prevprev,
48+
fields_full, fields_half = self.FComputer.compute_fields(
49+
fields_half, fields_prev, const_arrays, rho_beam_full, rho_beam_prev,
5050
currents_prev, currents_full
5151
)
5252

@@ -57,4 +57,4 @@ def step_dxi(
5757
particles_full, const_arrays
5858
)
5959

60-
return particles_full, fields_full, currents_full, currents_prev
60+
return particles_full, fields_full, currents_full

0 commit comments

Comments
 (0)