Skip to content

Commit 5f4ef50

Browse files
authored
Merge pull request #272 from lcpp-org/dev
Merge dev into main
2 parents 7f5b65b + 58f18d7 commit 5f4ef50

16 files changed

+335
-13
lines changed

Diff for: Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "RustBCA"
3-
version = "2.8.4"
3+
version = "2.9.0"
44
default-run = "RustBCA"
55
authors = ["Jon Drobny <[email protected]>", "Jon Drobny <[email protected]>"]
66
edition = "2021"
@@ -20,7 +20,7 @@ rand_distr = "0.4.3"
2020
toml = "0.7.4"
2121
anyhow = "1.0.71"
2222
itertools = "0.10.5"
23-
rayon = "1.7.0"
23+
rayon = "1.10.0"
2424
geo = {version = "0.25", optional = false}
2525
indicatif = {version = "0.15.0", features=["rayon"]}
2626
serde = { version = "1.0.163", features = ["derive"] }

Diff for: examples/boron_nitride_0D.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 0D geometry option only
12
[options]
23
name = "boron_nitride_"
34
weak_collision_order = 0

Diff for: examples/boron_nitride_sphere.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with SPHERE geometry option only
12
[options]
23
name = "boron_nitride_"
34
track_trajectories = true

Diff for: examples/boron_nitride_wire.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 2D geometry option only
12
[options]
23
name = "boron_nitride_"
34
weak_collision_order = 0

Diff for: examples/boron_nitride_wire_homogeneous.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 0D geometry option only
12
[options]
23
name = "boron_nitride_h_"
34
weak_collision_order = 0

Diff for: examples/layered_geometry.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 2D geometry option only
12
[options]
23
name = "2000.0eV_0.0001deg_He_TiO2_Al_Si"
34
track_trajectories = false

Diff for: examples/layered_geometry_1D.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 2D geometry option only
12
[options]
23
name = "2000.0eV_0.0001deg_He_TiO2_Al_Si"
34
track_trajectories = false

Diff for: examples/lithium_vapor_shield.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 1D geometry option only
12
[options]
23
name = "lithium_vapor_shield_"
34
track_trajectories = true

Diff for: examples/multiple_interaction_potentials.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 2D geometry input only
12
[options]
23
name = "2000.0eV_0.0001deg_He_H_TiO2_Al_Si"
34
track_trajectories = true

Diff for: examples/test_morse.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ def run_krc_morse_potential(energy, index, num_samples=10000, run_sim=True):
180180
R_E_2 = np.zeros(num_energies)
181181

182182
for index, energy in enumerate(energies):
183-
R_N[index], R_E[index] = run_krc_morse_potential(energy, index, num_samples=num_samples, run_sim=False)
184-
R_N_2[index], R_E_2[index] = run_morse_potential(energy, index, num_samples=num_samples, run_sim=False)
183+
R_N[index], R_E[index] = run_krc_morse_potential(energy, index, num_samples=num_samples, run_sim=True)
184+
R_N_2[index], R_E_2[index] = run_morse_potential(energy, index, num_samples=num_samples, run_sim=True)
185185

186186
plt.semilogx(energies, R_N, label='R_N Morse-Kr-C H-Ni, Es=1.5eV', color='purple')
187187
plt.semilogx(energies, R_N_2, label='R_N Morse H-Ni, Es=1.5eV', color='green')

Diff for: examples/test_rustbca.py

+103-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
def main():
1414

15+
1516
#test rotation to and from RustBCA coordinates
1617

1718
#nx, ny, nz is the normal vector (out of surface)
@@ -35,6 +36,31 @@ def main():
3536
assert(abs(uy) < 1e-6)
3637
assert(abs(uz) < 1e-6)
3738

39+
#test vectorized rotation to and from RustBCA coordinates
40+
41+
num_rot_test = 1000000
42+
43+
#nx, ny, nz is the normal vector (out of surface)
44+
nx = [-np.sqrt(2)/2]*num_rot_test
45+
ny = [-np.sqrt(2)/2]*num_rot_test
46+
nz = [0.0]*num_rot_test
47+
48+
#ux, uy, uz is the particle direction (simulation coordinates)
49+
ux = [1.0]*num_rot_test
50+
uy = [0.0]*num_rot_test
51+
uz = [0.0]*num_rot_test
52+
53+
start = time.time()
54+
ux, uy, uz = rotate_given_surface_normal_vec_py(nx, ny, nz, ux, uy, uz)
55+
ux, uy, uz = rotate_back_vec_py(nx, ny, nz, ux, uy, uz)
56+
stop = time.time()
57+
print(f'Time to rotate: {(stop - start)/num_rot_test} sec/vector')
58+
59+
#After rotating and rotating back, effect should be where you started (minus fp error)
60+
assert(abs(ux[0] - 1.0) < 1e-6)
61+
assert(abs(uy[0]) < 1e-6)
62+
assert(abs(uz[0]) < 1e-6)
63+
3864
#scripts/materials.py has a number of potential ions and targets
3965
ion = helium
4066
ion['Eb'] = 0.0
@@ -128,7 +154,7 @@ def main():
128154
print('Data processing complete.')
129155
print(f'RustBCA Y: {len(sputtered[:, 0])/number_ions} Yamamura Y: {yamamura_yield}')
130156
print(f'RustBCA R: {len(reflected[:, 0])/number_ions} Thomas R: {thomas}')
131-
print(f'Time per ion: {delta_time/number_ions*1e3} us/{ion["symbol"]}')
157+
print(f'Time per ion: {delta_time/number_ions} s/{ion["symbol"]}')
132158

133159
#Next up is the layered target version. I'll add a 50 Angstrom layer of W-H to the top of the target.
134160

@@ -145,14 +171,15 @@ def main():
145171

146172
print(f'Running RustBCA for {number_ions} {ion["symbol"]} ions on {target["symbol"]} with hydrogenated layer at {energies_eV[0]/1000.} keV...')
147173
print(f'This may take several minutes.')
148-
#Not the different argument order; when a breaking change is due, this will
174+
#Note the different argument order; when a breaking change is due, this will
149175
#be back-ported to the other bindings as well for consistency.
150176
output, incident, stopped = compound_bca_list_1D_py(
151177
ux, uy, uz, energies_eV, [ion['Z']]*number_ions,
152178
[ion['m']]*number_ions, [ion['Ec']]*number_ions, [ion['Es']]*number_ions, [target['Z'], 1.0], [target['m'], 1.008],
153179
[target['Ec'], 1.0], [target['Es'], 1.5], [target['Eb'], 0.0], [[target['n']/10**30, target['n']/10**30], [target['n']/10**30, 0.0]], [50.0, 1e6]
154180
)
155181

182+
156183
output = np.array(output)
157184

158185
Z = output[:, 0]
@@ -173,6 +200,80 @@ def main():
173200
plt.plot([50.0, 50.0], [0.0, np.max(heights)*1.1])
174201
plt.gca().set_ylim([0.0, np.max(heights)*1.1])
175202

203+
number_ions = 10000
204+
205+
#1 keV is above the He on W sputtering threshold of ~150 eV
206+
energies_eV = 1000.0*np.ones(number_ions)
207+
208+
#Working with angles of exactly 0 is problematic due to gimbal lock
209+
angle = 0.0001
210+
211+
#In RustBCA's 0D geometry, +x -> into the surface
212+
ux = np.cos(angle*np.pi/180.)*np.ones(number_ions)
213+
uy = np.sin(angle*np.pi/180.)*np.ones(number_ions)
214+
uz = np.zeros(number_ions)
215+
216+
Z1 = np.array([ion['Z']]*number_ions)
217+
m1 = np.array([ion['m']]*number_ions)
218+
Ec1 = np.array([ion['Ec']]*number_ions)
219+
Es1 = np.array([ion['Es']]*number_ions)
220+
221+
print(f'Running tracked RustBCA for {number_ions} {ion["symbol"]} ions on {target["symbol"]} with 1% {ion["symbol"]} at {energies_eV[0]/1000.} keV...')
222+
print(f'This may take several minutes.')
223+
224+
start = time.time()
225+
# Note that simple_bca_list_py expects number densities in 1/Angstrom^3
226+
output, incident, incident_index = compound_bca_list_tracked_py(
227+
energies_eV, ux, uy, uz, Z1, m1, Ec1, Es1,
228+
[target['Z'], ion['Z']], [target['m'], ion['m']],
229+
[target['Ec'], ion['Ec']], [target['Es'], ion['Es']], [target['n']/10**30, 0.01*target['n']/10**30],
230+
[target['Eb'], 0.0])
231+
stop = time.time()
232+
delta_time = stop - start
233+
234+
output = np.array(output)
235+
Z = output[:, 0]
236+
m = output[:, 1]
237+
E = output[:, 2]
238+
x = output[:, 3]
239+
y = output[:, 4]
240+
z = output[:, 5]
241+
ux = output[:, 6]
242+
uy = output[:, 7]
243+
uz = output[:, 8]
244+
245+
#For the python bindings, these conditionals can be used to distinguish
246+
#between sputtered, reflected, and implanted particles in the output list
247+
sputtered = output[np.logical_and(Z == target['Z'], E > 0), :]
248+
reflected = output[np.logical_and(Z == ion['Z'], x < 0), :]
249+
implanted = output[np.logical_and(Z == ion['Z'], x > 0), :]
250+
251+
plt.figure(1)
252+
plt.title(f'Sputtered {target["symbol"]} Energy Distribution')
253+
plt.xlabel('E [eV]')
254+
plt.ylabel('f(E) [A.U.]')
255+
plt.hist(sputtered[:, 2], bins=100, density=True, histtype='step')
256+
257+
plt.figure(2)
258+
plt.title(f'Implanted {ion["symbol"]} Depth Distribution')
259+
plt.xlabel('x [A]')
260+
plt.ylabel('f(x) [A.U.]')
261+
plt.hist(implanted[:, 3], bins=100, density=True, histtype='step')
262+
263+
thomas = thomas_reflection(ion, target, energies_eV[0])
264+
yamamura_yield = yamamura(ion, target, energies_eV[0])
265+
266+
print('Data processing complete.')
267+
print(f'RustBCA Y: {len(sputtered[:, 0])/number_ions} Yamamura Y: {yamamura_yield}')
268+
print(f'RustBCA R: {len(reflected[:, 0])/number_ions} Thomas R: {thomas}')
269+
print(f'Time per ion: {delta_time/number_ions} s/{ion["symbol"]}')
270+
271+
plt.figure()
272+
plt.plot(incident_index)
273+
plt.xlabel('Particle number')
274+
plt.ylabel('Particle index')
275+
plt.legend(['Incident', 'Indicies'])
276+
176277
plt.show()
177278

178279
if __name__ == '__main__':

Diff for: examples/titanium_dioxide_0D.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with 0D geometry option only
12
[options]
23
name = "10.0"
34
track_trajectories = false

Diff for: examples/tungsten_tiles_trimesh.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with TRIMESH geometry option only
12
[options]
23
name = "tungsten_tiles_"
34
track_trajectories = true

Diff for: examples/tungsten_twist_trimesh.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#Use with TRIMESH geometry option only
12
[options]
23
name = "tungsten_twist_"
34
track_trajectories = true

Diff for: src/geometry.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl Geometry for Mesh0D {
6666
let electronic_stopping_correction_factor = input.electronic_stopping_correction_factor;
6767

6868
let densities: Vec<f64> = input.densities.iter().map(|element| element/(length_unit).powi(3)).collect();
69+
assert!(densities.len() > 0, "Input Error: density list empty.");
6970

7071
let total_density: f64 = densities.iter().sum();
7172

@@ -135,6 +136,7 @@ impl Geometry for Mesh1D {
135136

136137
let layer_thicknesses = geometry_input.layer_thicknesses.clone();
137138
let electronic_stopping_correction_factors = geometry_input.electronic_stopping_correction_factors.clone();
139+
assert!(electronic_stopping_correction_factors.len() > 0, "Input Error: Electronic stopping correction factor list empty.");
138140
let n = layer_thicknesses.len();
139141

140142
let mut layers: Vec<Layer1D> = Vec::with_capacity(n);
@@ -433,7 +435,7 @@ impl Geometry for Mesh2D {
433435

434436
let simulation_boundary_points = geometry_input.simulation_boundary_points.clone();
435437
let electronic_stopping_correction_factors = geometry_input.electronic_stopping_correction_factors.clone();
436-
438+
assert!(electronic_stopping_correction_factors.len() > 0, "Input Error: Electronic stopping correction factor list empty.");
437439
let n = triangles.len();
438440

439441
let mut cells: Vec<Cell2D> = Vec::with_capacity(n);

0 commit comments

Comments
 (0)