Skip to content

Commit 4711853

Browse files
committed
Update tests to include morse potential when CPR is activated.
1 parent 2936a3a commit 4711853

File tree

1 file changed

+163
-124
lines changed

1 file changed

+163
-124
lines changed

src/tests.rs

Lines changed: 163 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,41 @@ fn test_surface_refraction() {
761761
#[test]
762762
fn test_momentum_conservation() {
763763

764+
765+
#[cfg(not(feature = "cpr_rootfinder"))]
766+
let potentials = vec![
767+
InteractionPotential::KR_C,
768+
InteractionPotential::MOLIERE,
769+
InteractionPotential::ZBL,
770+
InteractionPotential::LENZ_JENSEN
771+
];
772+
773+
#[cfg(feature = "cpr_rootfinder")]
774+
let potentials = vec![
775+
InteractionPotential::KR_C,
776+
InteractionPotential::MOLIERE,
777+
InteractionPotential::ZBL,
778+
InteractionPotential::LENZ_JENSEN,
779+
InteractionPotential::MORSE{D: 5.4971E-20, r0: 2.782E-10, alpha: 1.4198E10}
780+
];
781+
782+
let mut rootfinders = vec![Rootfinder::NEWTON{max_iterations: 100, tolerance: 1E-3}; 4];
783+
784+
//[[{"CPR"={n0=2, nmax=100, epsilon=1E-9, complex_threshold=1E-3, truncation_threshold=1E-9, far_from_zero=1E9, interval_limit=1E-12, derivative_free=true}}]]
785+
#[cfg(feature = "cpr_rootfinder")]
786+
rootfinders.push(
787+
Rootfinder::CPR{
788+
n0: 2,
789+
nmax: 100,
790+
epsilon: 1e-9,
791+
complex_threshold: 1e-3,
792+
truncation_threshold: 1e-9,
793+
far_from_zero: 1e9,
794+
interval_limit:1e-12,
795+
derivative_free: true
796+
}
797+
);
798+
764799
for direction in vec![(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (-1.0, 0.0, 0.0), (0.0, -1.0, 0.0), (0.0, 0.0, -1.0)] {
765800
for energy_eV in vec![1., 10., 100., 1000., 1000.] {
766801
//Aluminum
@@ -813,132 +848,136 @@ fn test_momentum_conservation() {
813848
let material_1: material::Material<geometry::Mesh2D> = material::Material::<geometry::Mesh2D>::new(&material_parameters, &geometry_input);
814849

815850
for high_energy_free_flight_paths in vec![true, false] {
816-
for potential in vec![InteractionPotential::KR_C, InteractionPotential::MOLIERE, InteractionPotential::ZBL, InteractionPotential::LENZ_JENSEN] {
851+
for (potential, root_finder) in potentials.iter().zip(rootfinders.clone()) {
817852
for scattering_integral in vec![ScatteringIntegral::MENDENHALL_WELLER, ScatteringIntegral::GAUSS_MEHLER{n_points: 10}, ScatteringIntegral::GAUSS_LEGENDRE] {
818-
for root_finder in vec![Rootfinder::NEWTON{max_iterations: 100, tolerance: 1E-3}] {
819-
820-
println!("Case: {} {} {} {}", energy_eV, high_energy_free_flight_paths, potential, scattering_integral);
821-
822-
let mut particle_1 = particle::Particle::new(m1, Z1, E1, Ec1, Es1, 0.0, x1, y1, z1, cosx, cosy, cosz, false, false, 0);
823-
824-
#[cfg(not(feature = "distributions"))]
825-
let options = Options {
826-
name: "test".to_string(),
827-
track_trajectories: false,
828-
track_recoils: true,
829-
track_recoil_trajectories: false,
830-
write_buffer_size: 8000,
831-
weak_collision_order: 0,
832-
suppress_deep_recoils: false,
833-
high_energy_free_flight_paths: high_energy_free_flight_paths,
834-
electronic_stopping_mode: ElectronicStoppingMode::INTERPOLATED,
835-
mean_free_path_model: MeanFreePathModel::LIQUID,
836-
interaction_potential: vec![vec![potential]],
837-
scattering_integral: vec![vec![scattering_integral]],
838-
num_threads: 1,
839-
num_chunks: 1,
840-
use_hdf5: false,
841-
root_finder: vec![vec![root_finder]],
842-
track_displacements: false,
843-
track_energy_losses: false,
844-
};
845-
846-
#[cfg(feature = "distributions")]
847-
let options = Options {
848-
name: "test".to_string(),
849-
track_trajectories: false,
850-
track_recoils: true,
851-
track_recoil_trajectories: false,
852-
write_buffer_size: 8000,
853-
weak_collision_order: 0,
854-
suppress_deep_recoils: false,
855-
high_energy_free_flight_paths: high_energy_free_flight_paths,
856-
electronic_stopping_mode: ElectronicStoppingMode::INTERPOLATED,
857-
mean_free_path_model: MeanFreePathModel::LIQUID,
858-
interaction_potential: vec![vec![potential]],
859-
scattering_integral: vec![vec![scattering_integral]],
860-
num_threads: 1,
861-
num_chunks: 1,
862-
use_hdf5: false,
863-
root_finder: vec![vec![root_finder]],
864-
track_displacements: false,
865-
track_energy_losses: false,
866-
energy_min: 0.0,
867-
energy_max: 10.0,
868-
energy_num: 11,
869-
angle_min: 0.0,
870-
angle_max: 90.0,
871-
angle_num: 11,
872-
x_min: 0.0,
873-
y_min: -10.0,
874-
z_min: -10.0,
875-
x_max: 10.0,
876-
y_max: 10.0,
877-
z_max: 10.0,
878-
x_num: 11,
879-
y_num: 11,
880-
z_num: 11,
881-
};
882-
883-
let binary_collision_geometries = bca::determine_mfp_phi_impact_parameter(&mut particle_1, &material_1, &options);
884-
885-
println!("Phi: {} rad p: {} Angstrom mfp: {} Angstrom", binary_collision_geometries[0].phi_azimuthal,
886-
binary_collision_geometries[0].impact_parameter/ANGSTROM,
887-
binary_collision_geometries[0].mfp/ANGSTROM);
888-
889-
let (species_index, mut particle_2) = bca::choose_collision_partner(&mut particle_1, &material_1,
890-
&binary_collision_geometries[0], &options);
891-
892-
let mom1_0 = particle_1.get_momentum();
893-
let mom2_0 = particle_2.get_momentum();
894-
895-
let initial_momentum = mom1_0.add(&mom2_0);
896-
897-
let binary_collision_result = bca::calculate_binary_collision(&particle_1,
898-
&particle_2, &binary_collision_geometries[0], &options).unwrap();
899-
900-
println!("E_recoil: {} eV Psi: {} rad Psi_recoil: {} rad", binary_collision_result.recoil_energy/EV,
901-
binary_collision_result.psi,
902-
binary_collision_result.psi_recoil);
903-
904-
println!("Initial Energies: {} eV {} eV", particle_1.E/EV, particle_2.E/EV);
905-
906-
//Energy transfer to recoil
907-
particle_2.E = binary_collision_result.recoil_energy - material_1.average_bulk_binding_energy(particle_2.pos.x, particle_2.pos.y, particle_2.pos.z);
908-
909-
//Rotate particle 1, 2 by lab frame scattering angles
910-
particle_1.rotate(binary_collision_result.psi,
911-
binary_collision_geometries[0].phi_azimuthal);
912-
913-
particle_2.rotate(-binary_collision_result.psi_recoil,
914-
binary_collision_geometries[0].phi_azimuthal);
915-
916-
//Subtract total energy from all simultaneous collisions and electronic stopping
917-
particle_1.E += -binary_collision_result.recoil_energy;
918-
bca::subtract_electronic_stopping_energy(&mut particle_1, &material_1, 0.,
919-
0., particle_2.Z, species_index, &options);
920-
921-
let mom1_1 = particle_1.get_momentum();
922-
let mom2_1 = particle_2.get_momentum();
923-
924-
let final_momentum = mom1_1.add(&mom2_1);
925-
926-
println!("Final Energies: {} eV {} eV", particle_1.E/EV, particle_2.E/EV);
927-
println!("X: {} {} {}% Error", initial_momentum.x/ANGSTROM/AMU, final_momentum.x/ANGSTROM/AMU, 100.*(final_momentum.x - initial_momentum.x)/initial_momentum.magnitude());
928-
println!("Y: {} {} {}% Error", initial_momentum.y/ANGSTROM/AMU, final_momentum.y/ANGSTROM/AMU, 100.*(final_momentum.y - initial_momentum.y)/initial_momentum.magnitude());
929-
println!("Z: {} {} {}% Error", initial_momentum.z/ANGSTROM/AMU, final_momentum.z/ANGSTROM/AMU, 100.*(final_momentum.z - initial_momentum.z)/initial_momentum.magnitude());
930-
println!();
931-
932-
assert!(approx_eq!(f64, initial_momentum.x/ANGSTROM/AMU, final_momentum.x/ANGSTROM/AMU, epsilon = 1000.));
933-
assert!(approx_eq!(f64, initial_momentum.y/ANGSTROM/AMU, final_momentum.y/ANGSTROM/AMU, epsilon = 1000.));
934-
assert!(approx_eq!(f64, initial_momentum.z/ANGSTROM/AMU, final_momentum.z/ANGSTROM/AMU, epsilon = 1000.));
935-
936-
assert!(!particle_1.E.is_nan());
937-
assert!(!particle_2.E.is_nan());
938-
assert!(!initial_momentum.x.is_nan());
939-
assert!(!initial_momentum.x.is_nan());
940-
assert!(!initial_momentum.x.is_nan());
853+
854+
//Skip incompatible combination
855+
match (root_finder, scattering_integral) {
856+
(Rootfinder::CPR{..}, ScatteringIntegral::MENDENHALL_WELLER) => continue,
857+
_ => {}
941858
}
859+
860+
println!("Case: {} {} {} {}", energy_eV, high_energy_free_flight_paths, potential, scattering_integral);
861+
862+
let mut particle_1 = particle::Particle::new(m1, Z1, E1, Ec1, Es1, 0.0, x1, y1, z1, cosx, cosy, cosz, false, false, 0);
863+
864+
#[cfg(not(feature = "distributions"))]
865+
let options = Options {
866+
name: "test".to_string(),
867+
track_trajectories: false,
868+
track_recoils: true,
869+
track_recoil_trajectories: false,
870+
write_buffer_size: 8000,
871+
weak_collision_order: 0,
872+
suppress_deep_recoils: false,
873+
high_energy_free_flight_paths: high_energy_free_flight_paths,
874+
electronic_stopping_mode: ElectronicStoppingMode::INTERPOLATED,
875+
mean_free_path_model: MeanFreePathModel::LIQUID,
876+
interaction_potential: vec![vec![*potential]],
877+
scattering_integral: vec![vec![scattering_integral]],
878+
num_threads: 1,
879+
num_chunks: 1,
880+
use_hdf5: false,
881+
root_finder: vec![vec![root_finder]],
882+
track_displacements: false,
883+
track_energy_losses: false,
884+
};
885+
886+
#[cfg(feature = "distributions")]
887+
let options = Options {
888+
name: "test".to_string(),
889+
track_trajectories: false,
890+
track_recoils: true,
891+
track_recoil_trajectories: false,
892+
write_buffer_size: 8000,
893+
weak_collision_order: 0,
894+
suppress_deep_recoils: false,
895+
high_energy_free_flight_paths: high_energy_free_flight_paths,
896+
electronic_stopping_mode: ElectronicStoppingMode::INTERPOLATED,
897+
mean_free_path_model: MeanFreePathModel::LIQUID,
898+
interaction_potential: vec![vec![potential]],
899+
scattering_integral: vec![vec![scattering_integral]],
900+
num_threads: 1,
901+
num_chunks: 1,
902+
use_hdf5: false,
903+
root_finder: vec![vec![root_finder]],
904+
track_displacements: false,
905+
track_energy_losses: false,
906+
energy_min: 0.0,
907+
energy_max: 10.0,
908+
energy_num: 11,
909+
angle_min: 0.0,
910+
angle_max: 90.0,
911+
angle_num: 11,
912+
x_min: 0.0,
913+
y_min: -10.0,
914+
z_min: -10.0,
915+
x_max: 10.0,
916+
y_max: 10.0,
917+
z_max: 10.0,
918+
x_num: 11,
919+
y_num: 11,
920+
z_num: 11,
921+
};
922+
923+
let binary_collision_geometries = bca::determine_mfp_phi_impact_parameter(&mut particle_1, &material_1, &options);
924+
925+
println!("Phi: {} rad p: {} Angstrom mfp: {} Angstrom", binary_collision_geometries[0].phi_azimuthal,
926+
binary_collision_geometries[0].impact_parameter/ANGSTROM,
927+
binary_collision_geometries[0].mfp/ANGSTROM);
928+
929+
let (species_index, mut particle_2) = bca::choose_collision_partner(&mut particle_1, &material_1,
930+
&binary_collision_geometries[0], &options);
931+
932+
let mom1_0 = particle_1.get_momentum();
933+
let mom2_0 = particle_2.get_momentum();
934+
935+
let initial_momentum = mom1_0.add(&mom2_0);
936+
937+
let binary_collision_result = bca::calculate_binary_collision(&particle_1,
938+
&particle_2, &binary_collision_geometries[0], &options).unwrap();
939+
940+
println!("E_recoil: {} eV Psi: {} rad Psi_recoil: {} rad", binary_collision_result.recoil_energy/EV,
941+
binary_collision_result.psi,
942+
binary_collision_result.psi_recoil);
943+
944+
println!("Initial Energies: {} eV {} eV", particle_1.E/EV, particle_2.E/EV);
945+
946+
//Energy transfer to recoil
947+
particle_2.E = binary_collision_result.recoil_energy - material_1.average_bulk_binding_energy(particle_2.pos.x, particle_2.pos.y, particle_2.pos.z);
948+
949+
//Rotate particle 1, 2 by lab frame scattering angles
950+
particle_1.rotate(binary_collision_result.psi,
951+
binary_collision_geometries[0].phi_azimuthal);
952+
953+
particle_2.rotate(-binary_collision_result.psi_recoil,
954+
binary_collision_geometries[0].phi_azimuthal);
955+
956+
//Subtract total energy from all simultaneous collisions and electronic stopping
957+
particle_1.E += -binary_collision_result.recoil_energy;
958+
bca::subtract_electronic_stopping_energy(&mut particle_1, &material_1, 0.,
959+
0., particle_2.Z, species_index, &options);
960+
961+
let mom1_1 = particle_1.get_momentum();
962+
let mom2_1 = particle_2.get_momentum();
963+
964+
let final_momentum = mom1_1.add(&mom2_1);
965+
966+
println!("Final Energies: {} eV {} eV", particle_1.E/EV, particle_2.E/EV);
967+
println!("X: {} {} {}% Error", initial_momentum.x/ANGSTROM/AMU, final_momentum.x/ANGSTROM/AMU, 100.*(final_momentum.x - initial_momentum.x)/initial_momentum.magnitude());
968+
println!("Y: {} {} {}% Error", initial_momentum.y/ANGSTROM/AMU, final_momentum.y/ANGSTROM/AMU, 100.*(final_momentum.y - initial_momentum.y)/initial_momentum.magnitude());
969+
println!("Z: {} {} {}% Error", initial_momentum.z/ANGSTROM/AMU, final_momentum.z/ANGSTROM/AMU, 100.*(final_momentum.z - initial_momentum.z)/initial_momentum.magnitude());
970+
println!();
971+
972+
assert!(approx_eq!(f64, initial_momentum.x/ANGSTROM/AMU, final_momentum.x/ANGSTROM/AMU, epsilon = 1000.));
973+
assert!(approx_eq!(f64, initial_momentum.y/ANGSTROM/AMU, final_momentum.y/ANGSTROM/AMU, epsilon = 1000.));
974+
assert!(approx_eq!(f64, initial_momentum.z/ANGSTROM/AMU, final_momentum.z/ANGSTROM/AMU, epsilon = 1000.));
975+
976+
assert!(!particle_1.E.is_nan());
977+
assert!(!particle_2.E.is_nan());
978+
assert!(!initial_momentum.x.is_nan());
979+
assert!(!initial_momentum.x.is_nan());
980+
assert!(!initial_momentum.x.is_nan());
942981
}
943982
}
944983
}

0 commit comments

Comments
 (0)