9
9
10
10
# Helper function #
11
11
12
- def get_beam_substepping_step (xp : np ):
13
- def beam_substepping_step (q_m , pz , substepping_energy ):
14
- dt = xp .ones_like (q_m , dtype = xp .float64 )
15
- max_dt = xp .sqrt (
16
- xp .sqrt (1 / q_m ** 2 + pz ** 2 ) / substepping_energy )
17
-
18
- a = xp .ceil (xp .log2 (dt / max_dt ))
19
- a [a < 0 ] = 0
20
- dt /= 2 ** a
12
+ # NOTE: We have to write these functions separately and we don't merge them,
13
+ # because other implementation options (including from old commits) led
14
+ # to an illegal memory access when computing on a GPU. The problem is
15
+ # probably in the internals of the cupy library. The specific simulation
16
+ # settings will still create the problem, but in different places.
17
+
18
+ @nb .njit
19
+ def beam_substepping_step_numba (q_m , pz , substepping_energy ):
20
+ dt = np .ones_like (q_m , dtype = np .float64 )
21
+ max_dt = np .sqrt (np .sqrt (1 / q_m ** 2 + pz ** 2 ) / substepping_energy )
22
+ for i in range (len (q_m )):
23
+ while dt [i ] > max_dt [i ]:
24
+ dt [i ] /= 2.0
25
+ return dt
26
+
27
+
28
+ def get_beam_substepping_step_cupy ():
29
+ import cupy as cp
30
+
31
+ calculate_substepping_step = cp .ElementwiseKernel (
32
+ in_params = "T q_m, T pz, float64 substepping_energy" ,
33
+ out_params = "T dt" ,
34
+ operation = """
35
+ T max_dt = sqrt(sqrt(1 / (q_m*q_m) + pz*pz) / substepping_energy);
36
+ while (dt > max_dt){
37
+ dt /= 2;
38
+ }
39
+ """ )
21
40
41
+ def beam_substepping_step (q_m , pz , substepping_energy ):
42
+ dt = cp .ones_like (q_m , dtype = cp .float64 )
43
+ calculate_substepping_step (q_m , pz , substepping_energy , dt )
22
44
return dt
23
45
24
- if xp is np :
25
- return nb .njit (beam_substepping_step )
26
-
27
46
return beam_substepping_step
28
47
29
48
@@ -39,7 +58,12 @@ def __init__(self, config: Config):
39
58
40
59
self .deposit = get_deposit_beam (config )
41
60
self .move_particles = get_move_beam_particles (config )
42
- self .beam_substepping_step = get_beam_substepping_step (self .xp )
61
+
62
+ pu_type = config .get ('processing-unit-type' ).lower ()
63
+ if pu_type == 'cpu' :
64
+ self .beam_substepping_step = beam_substepping_step_numba
65
+ if pu_type == 'gpu' :
66
+ self .beam_substepping_step = get_beam_substepping_step_cupy ()
43
67
44
68
# Helper functions for one time step cicle:
45
69
@@ -101,9 +125,8 @@ def move_beam_layer(self, beam_layer: BeamParticles, fell_size,
101
125
beam_layer_idx , beam_layer , fields_after_layer ,
102
126
fields_before_layer , lost_idxes , moved_idxes , fell_idxes )
103
127
104
- indexes = self .xp .arange (beam_layer .id .size )
105
- lost = beam_layer .get_layer (indexes [lost_idxes ])
106
- moved = beam_layer .get_layer (indexes [moved_idxes ])
107
- fell = beam_layer .get_layer (indexes [fell_idxes ])
128
+ lost = beam_layer .get_layer (lost_idxes )
129
+ moved = beam_layer .get_layer (moved_idxes )
130
+ fell = beam_layer .get_layer (fell_idxes )
108
131
109
132
return lost , moved , fell
0 commit comments