@@ -761,6 +761,41 @@ fn test_surface_refraction() {
761
761
#[ test]
762
762
fn test_momentum_conservation ( ) {
763
763
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
+
764
799
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 ) ] {
765
800
for energy_eV in vec ! [ 1. , 10. , 100. , 1000. , 1000. ] {
766
801
//Aluminum
@@ -813,132 +848,136 @@ fn test_momentum_conservation() {
813
848
let material_1: material:: Material < geometry:: Mesh2D > = material:: Material :: < geometry:: Mesh2D > :: new ( & material_parameters, & geometry_input) ;
814
849
815
850
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 ( ) ) {
817
852
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
+ _ => { }
941
858
}
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( ) ) ;
942
981
}
943
982
}
944
983
}
0 commit comments