@@ -81,6 +81,7 @@ pub fn pybca(py: Python, m: &PyModule) -> PyResult<()> {
81
81
m. add_function ( wrap_pyfunction ! ( simple_bca_py, m) ?) ?;
82
82
m. add_function ( wrap_pyfunction ! ( simple_bca_list_py, m) ?) ?;
83
83
m. add_function ( wrap_pyfunction ! ( compound_bca_list_py, m) ?) ?;
84
+ m. add_function ( wrap_pyfunction ! ( compound_bca_list_1D_py, m) ?) ?;
84
85
Ok ( ( ) )
85
86
}
86
87
@@ -1173,6 +1174,212 @@ pub fn compound_bca_list_py(energies: Vec<f64>, ux: Vec<f64>, uy: Vec<f64>, uz:
1173
1174
( total_output, incident)
1174
1175
}
1175
1176
1177
+ #[ cfg( feature = "python" ) ]
1178
+ ///compound_bca_list_1D_py(ux, uy, uz, energy, Z1, m1, Ec1, Es1, Z2, m2, Ec2, Es2, Eb2 n2, dx)
1179
+ /// runs a BCA simulation for a list of particles and outputs a list of sputtered, reflected, and implanted particles.
1180
+ /// Args:
1181
+ /// energies (list(f64)): initial ion energies in eV.
1182
+ /// ux (list(f64)): initial ion directions x. ux != 0.0 to avoid gimbal lock
1183
+ /// uy (list(f64)): initial ion directions y.
1184
+ /// uz (list(f64)): initial ion directions z.
1185
+ /// Z1 (list(f64)): initial ion atomic numbers.
1186
+ /// m1 (list(f64)): initial ion masses in amu.
1187
+ /// Ec1 (list(f64)): ion cutoff energies in eV. If ion energy < Ec1, it stops in the material.
1188
+ /// Es1 (list(f64)): ion surface binding energies. Assumed planar.
1189
+ /// Z2 (list(f64)): target material species atomic numbers.
1190
+ /// m2 (list(f64)): target material species masses in amu.
1191
+ /// Ec2 (list(f64)): target material species cutoff energies in eV. If recoil energy < Ec2, it stops in the material.
1192
+ /// Es2 (list(f64)): target species surface binding energies. Assumed planar.
1193
+ /// Eb2 (list(f64)): target material species bulk binding energies in eV.
1194
+ /// n2 (list(list(f64))): target material species atomic number densities in inverse cubic Angstroms.
1195
+ /// dx (list(f64)): target material layer thicknesses starting at surface.
1196
+ /// Returns:
1197
+ /// output (NX9 list of f64): each row in the list represents an output particle (implanted,
1198
+ /// sputtered, or reflected). Each row consists of:
1199
+ /// [Z, m (amu), E (eV), x, y, z, (angstrom), ux, uy, uz]
1200
+ /// incident (list(bool)): whether each row of output was an incident ion or originated in the target
1201
+ /// stopped (list(bool)): whether each row of output is associated with a particle that stopped in the target
1202
+ #[ pyfunction]
1203
+ pub fn compound_bca_list_1D_py ( ux : Vec < f64 > , uy : Vec < f64 > , uz : Vec < f64 > , energies : Vec < f64 > , Z1 : Vec < f64 > , m1 : Vec < f64 > , Ec1 : Vec < f64 > , Es1 : Vec < f64 > , Z2 : Vec < f64 > , m2 : Vec < f64 > , Ec2 : Vec < f64 > , Es2 : Vec < f64 > , Eb2 : Vec < f64 > , n2 : Vec < Vec < f64 > > , dx : Vec < f64 > ) -> ( Vec < [ f64 ; 9 ] > , Vec < bool > , Vec < bool > ) {
1204
+ let mut total_output = vec ! [ ] ;
1205
+ let mut incident = vec ! [ ] ;
1206
+ let mut stopped = vec ! [ ] ;
1207
+
1208
+ let num_layers_target = n2. len ( ) ;
1209
+ let num_species = Z2 . len ( ) ;
1210
+ let num_incident_ions = energies. len ( ) ;
1211
+
1212
+ assert_eq ! ( ux. len( ) , num_incident_ions, "Input error: list of x-directions is not the same length as list of incident energies." ) ;
1213
+ assert_eq ! ( uy. len( ) , num_incident_ions, "Input error: list of y-directions is not the same length as list of incident energies." ) ;
1214
+ assert_eq ! ( uz. len( ) , num_incident_ions, "Input error: list of z-directions is not the same length as list of incident energies." ) ;
1215
+ assert_eq ! ( Z1 . len( ) , num_incident_ions, "Input error: list of incident atomic numbers is not the same length as list of incident energies." ) ;
1216
+ assert_eq ! ( m1. len( ) , num_incident_ions, "Input error: list of incident atomic masses is not the same length as list of incident energies." ) ;
1217
+ assert_eq ! ( Es1 . len( ) , num_incident_ions, "Input error: list of incident surface binding energies is not the same length as list of incident energies." ) ;
1218
+ assert_eq ! ( Ec1 . len( ) , num_incident_ions, "Input error: list of incident cutoff energies is not the same length as list of incident energies." ) ;
1219
+
1220
+ assert_eq ! ( m2. len( ) , num_species, "Input error: list of target atomic masses is not the same length as atomic numbers." ) ;
1221
+ assert_eq ! ( Ec2 . len( ) , num_species, "Input error: list of target cutoff energies is not the same length as atomic numbers." ) ;
1222
+ assert_eq ! ( Es2 . len( ) , num_species, "Input error: list of target surface binding energies is not the same length as atomic numbers." ) ;
1223
+ assert_eq ! ( Eb2 . len( ) , num_species, "Input error: list of target bulk binding energies is not the same length as atomic numbers." ) ;
1224
+ assert_eq ! ( n2[ 0 ] . len( ) , num_species, "Input error: first layer list of target number densities is not the same length as atomic numbers." ) ;
1225
+
1226
+ assert_eq ! ( n2[ 0 ] . len( ) , num_species, "Input error: first layer species list of target number densities is not the same length as atomic numbers." ) ;
1227
+ assert_eq ! ( dx. len( ) , num_layers_target, "Input error: number of layer thicknesses not the same as number of layers in atomic densities list." ) ;
1228
+
1229
+ #[ cfg( feature = "distributions" ) ]
1230
+ let options = Options {
1231
+ name : "test" . to_string ( ) ,
1232
+ track_trajectories : false ,
1233
+ track_recoils : true ,
1234
+ track_recoil_trajectories : false ,
1235
+ write_buffer_size : 8000 ,
1236
+ weak_collision_order : 3 ,
1237
+ suppress_deep_recoils : true ,
1238
+ high_energy_free_flight_paths : true ,
1239
+ electronic_stopping_mode : ElectronicStoppingMode :: LOW_ENERGY_NONLOCAL ,
1240
+ mean_free_path_model : MeanFreePathModel :: LIQUID ,
1241
+ interaction_potential : vec ! [ vec![ InteractionPotential :: KR_C ] ] ,
1242
+ scattering_integral : vec ! [ vec![ ScatteringIntegral :: MENDENHALL_WELLER ] ] ,
1243
+ num_threads : 1 ,
1244
+ num_chunks : 1 ,
1245
+ use_hdf5 : false ,
1246
+ root_finder : vec ! [ vec![ Rootfinder :: DEFAULTNEWTON ] ] ,
1247
+ track_displacements : false ,
1248
+ track_energy_losses : false ,
1249
+ energy_min : 0.0 ,
1250
+ energy_max : 10.0 ,
1251
+ energy_num : 11 ,
1252
+ angle_min : 0.0 ,
1253
+ angle_max : 90.0 ,
1254
+ angle_num : 11 ,
1255
+ x_min : 0.0 ,
1256
+ y_min : -10.0 ,
1257
+ z_min : -10.0 ,
1258
+ x_max : 10.0 ,
1259
+ y_max : 10.0 ,
1260
+ z_max : 10.0 ,
1261
+ x_num : 11 ,
1262
+ y_num : 11 ,
1263
+ z_num : 11 ,
1264
+ } ;
1265
+
1266
+ #[ cfg( not( feature = "distributions" ) ) ]
1267
+ let options = Options {
1268
+ name : "test" . to_string ( ) ,
1269
+ track_trajectories : false ,
1270
+ track_recoils : true ,
1271
+ track_recoil_trajectories : false ,
1272
+ write_buffer_size : 8000 ,
1273
+ weak_collision_order : 3 ,
1274
+ suppress_deep_recoils : true ,
1275
+ high_energy_free_flight_paths : false ,
1276
+ electronic_stopping_mode : ElectronicStoppingMode :: LOW_ENERGY_NONLOCAL ,
1277
+ mean_free_path_model : MeanFreePathModel :: LIQUID ,
1278
+ interaction_potential : vec ! [ vec![ InteractionPotential :: KR_C ] ] ,
1279
+ scattering_integral : vec ! [ vec![ ScatteringIntegral :: MENDENHALL_WELLER ] ] ,
1280
+ num_threads : 1 ,
1281
+ num_chunks : 1 ,
1282
+ use_hdf5 : false ,
1283
+ root_finder : vec ! [ vec![ Rootfinder :: DEFAULTNEWTON ] ] ,
1284
+ track_displacements : false ,
1285
+ track_energy_losses : false ,
1286
+ } ;
1287
+
1288
+ let y = 0.0 ;
1289
+ let z = 0.0 ;
1290
+
1291
+ let material_parameters = material:: MaterialParameters {
1292
+ energy_unit : "EV" . to_string ( ) ,
1293
+ mass_unit : "AMU" . to_string ( ) ,
1294
+ Eb : Eb2 ,
1295
+ Es : Es2 ,
1296
+ Ec : Ec2 ,
1297
+ Z : Z2 ,
1298
+ m : m2,
1299
+ interaction_index : vec ! [ 0 ; num_species] ,
1300
+ surface_binding_model : SurfaceBindingModel :: INDIVIDUAL ,
1301
+ bulk_binding_model : BulkBindingModel :: INDIVIDUAL ,
1302
+ } ;
1303
+
1304
+ let geometry_input = geometry:: Mesh1DInput {
1305
+ length_unit : "ANGSTROM" . to_string ( ) ,
1306
+ densities : n2,
1307
+ layer_thicknesses : dx,
1308
+ electronic_stopping_correction_factors : vec ! [ 1.0 ; num_layers_target]
1309
+ } ;
1310
+
1311
+ let m = material:: Material :: < Mesh1D > :: new ( & material_parameters, & geometry_input) ;
1312
+
1313
+ let x = -m. geometry . top_energy_barrier_thickness /2. ;
1314
+
1315
+ let mut index: usize = 0 ;
1316
+ for ( ( ( ( ( ( ( E1_ , ux_) , uy_) , uz_) , Z1_ ) , Ec1_ ) , Es1_ ) , m1_) in energies. iter ( ) . zip ( ux) . zip ( uy) . zip ( uz) . zip ( Z1 ) . zip ( Ec1 ) . zip ( Es1 ) . zip ( m1) {
1317
+
1318
+ let mut dir = Vector :: new ( ux_, uy_, uz_) ;
1319
+ dir. normalize ( ) ;
1320
+
1321
+ let mut energy_out;
1322
+ let p = particle:: Particle {
1323
+ m : m1_* AMU ,
1324
+ Z : Z1_ ,
1325
+ E : E1_ * EV ,
1326
+ Ec : Ec1_ * EV ,
1327
+ Es : Es1_ * EV ,
1328
+ pos : Vector :: new ( x, y, z) ,
1329
+ dir : dir,
1330
+ pos_origin : Vector :: new ( x, y, z) ,
1331
+ pos_old : Vector :: new ( x, y, z) ,
1332
+ dir_old : dir,
1333
+ energy_origin : E1_ * EV ,
1334
+ asymptotic_deflection : 0.0 ,
1335
+ stopped : false ,
1336
+ left : false ,
1337
+ incident : true ,
1338
+ first_step : true ,
1339
+ trajectory : vec ! [ ] ,
1340
+ energies : vec ! [ ] ,
1341
+ track_trajectories : false ,
1342
+ number_collision_events : 0 ,
1343
+ backreflected : false ,
1344
+ interaction_index : 0 ,
1345
+ weight : 0.0 ,
1346
+ tag : 0 ,
1347
+ tracked_vector : Vector :: new ( 0. , 0. , 0. ) ,
1348
+ } ;
1349
+
1350
+ let output = bca:: single_ion_bca ( p, & m, & options) ;
1351
+
1352
+ for particle in output {
1353
+ if ( particle. left ) | ( particle. incident ) {
1354
+
1355
+ incident. push ( particle. incident ) ;
1356
+ stopped. push ( particle. stopped ) ;
1357
+
1358
+ if particle. stopped {
1359
+ energy_out = 0.
1360
+ } else {
1361
+ energy_out = particle. E /EV
1362
+ }
1363
+ total_output. push (
1364
+ [
1365
+ particle. Z ,
1366
+ particle. m /AMU ,
1367
+ energy_out,
1368
+ particle. pos . x /ANGSTROM ,
1369
+ particle. pos . y /ANGSTROM ,
1370
+ particle. pos . z /ANGSTROM ,
1371
+ particle. dir . x ,
1372
+ particle. dir . y ,
1373
+ particle. dir . z ,
1374
+ ]
1375
+ ) ;
1376
+ }
1377
+ }
1378
+ index += 1 ;
1379
+ }
1380
+ ( total_output, incident, stopped)
1381
+ }
1382
+
1176
1383
#[ cfg( feature = "python" ) ]
1177
1384
/// simple_bca_py( x, y, z, ux, uy, uz, energy, Z1, m1, Ec1, Es1, Z2, m2, Ec2, Es2, n2, Eb2)
1178
1385
/// --
0 commit comments