xcoll 0.3.5__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. xcoll/__init__.py +12 -4
  2. xcoll/beam_elements/__init__.py +7 -5
  3. xcoll/beam_elements/absorber.py +41 -7
  4. xcoll/beam_elements/base.py +1161 -244
  5. xcoll/beam_elements/collimators_src/black_absorber.h +118 -0
  6. xcoll/beam_elements/collimators_src/black_crystal.h +111 -0
  7. xcoll/beam_elements/collimators_src/everest_block.h +40 -28
  8. xcoll/beam_elements/collimators_src/everest_collimator.h +129 -50
  9. xcoll/beam_elements/collimators_src/everest_crystal.h +217 -73
  10. xcoll/beam_elements/everest.py +60 -113
  11. xcoll/colldb.py +250 -750
  12. xcoll/general.py +2 -2
  13. xcoll/headers/checks.h +1 -1
  14. xcoll/headers/particle_states.h +2 -2
  15. xcoll/initial_distribution.py +195 -0
  16. xcoll/install.py +177 -0
  17. xcoll/interaction_record/__init__.py +1 -0
  18. xcoll/interaction_record/interaction_record.py +252 -0
  19. xcoll/interaction_record/interaction_record_src/interaction_record.h +98 -0
  20. xcoll/{impacts → interaction_record}/interaction_types.py +11 -4
  21. xcoll/line_tools.py +83 -0
  22. xcoll/lossmap.py +209 -0
  23. xcoll/manager.py +2 -937
  24. xcoll/rf_sweep.py +1 -1
  25. xcoll/scattering_routines/everest/amorphous.h +239 -0
  26. xcoll/scattering_routines/everest/channeling.h +245 -0
  27. xcoll/scattering_routines/everest/crystal_parameters.h +137 -0
  28. xcoll/scattering_routines/everest/everest.h +8 -30
  29. xcoll/scattering_routines/everest/everest.py +13 -10
  30. xcoll/scattering_routines/everest/jaw.h +27 -197
  31. xcoll/scattering_routines/everest/materials.py +2 -0
  32. xcoll/scattering_routines/everest/multiple_coulomb_scattering.h +31 -10
  33. xcoll/scattering_routines/everest/nuclear_interaction.h +86 -0
  34. xcoll/scattering_routines/geometry/__init__.py +6 -0
  35. xcoll/scattering_routines/geometry/collimator_geometry.h +219 -0
  36. xcoll/scattering_routines/geometry/crystal_geometry.h +150 -0
  37. xcoll/scattering_routines/geometry/geometry.py +26 -0
  38. xcoll/scattering_routines/geometry/get_s.h +92 -0
  39. xcoll/scattering_routines/geometry/methods.h +111 -0
  40. xcoll/scattering_routines/geometry/objects.h +154 -0
  41. xcoll/scattering_routines/geometry/rotation.h +23 -0
  42. xcoll/scattering_routines/geometry/segments.h +226 -0
  43. xcoll/scattering_routines/geometry/sort.h +184 -0
  44. {xcoll-0.3.5.dist-info → xcoll-0.4.0.dist-info}/METADATA +1 -1
  45. {xcoll-0.3.5.dist-info → xcoll-0.4.0.dist-info}/RECORD +48 -33
  46. xcoll/beam_elements/collimators_src/absorber.h +0 -141
  47. xcoll/collimator_settings.py +0 -457
  48. xcoll/impacts/__init__.py +0 -1
  49. xcoll/impacts/impacts.py +0 -102
  50. xcoll/impacts/impacts_src/impacts.h +0 -99
  51. xcoll/scattering_routines/everest/crystal.h +0 -1302
  52. xcoll/scattering_routines/everest/scatter.h +0 -169
  53. xcoll/scattering_routines/everest/scatter_crystal.h +0 -260
  54. {xcoll-0.3.5.dist-info → xcoll-0.4.0.dist-info}/LICENSE +0 -0
  55. {xcoll-0.3.5.dist-info → xcoll-0.4.0.dist-info}/NOTICE +0 -0
  56. {xcoll-0.3.5.dist-info → xcoll-0.4.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,118 @@
1
+ // copyright ############################### #
2
+ // This file is part of the Xcoll Package. #
3
+ // Copyright (c) CERN, 2024. #
4
+ // ######################################### #
5
+
6
+ #ifndef XCOLL_ABSORBER_H
7
+ #define XCOLL_ABSORBER_H
8
+
9
+
10
+ /*gpufun*/
11
+ CollimatorGeometry BlackAbsorber_init_geometry(BlackAbsorberData el, LocalParticle* part0, int8_t active){
12
+ CollimatorGeometry cg = (CollimatorGeometry) malloc(sizeof(CollimatorGeometry_));
13
+ if (active){ // This is needed in order to avoid that the initialisation is called during a twiss!
14
+ // Jaw corners (with tilts)
15
+ cg->jaw_LU = BlackAbsorberData_get__jaw_LU(el);
16
+ cg->jaw_RU = BlackAbsorberData_get__jaw_RU(el);
17
+ // Get angles of jaws
18
+ cg->sin_zL = BlackAbsorberData_get__sin_zL(el);
19
+ cg->cos_zL = BlackAbsorberData_get__cos_zL(el);
20
+ cg->sin_zR = BlackAbsorberData_get__sin_zR(el);
21
+ cg->cos_zR = BlackAbsorberData_get__cos_zR(el);
22
+ cg->sin_zDiff = BlackAbsorberData_get__sin_zDiff(el);
23
+ cg->cos_zDiff = BlackAbsorberData_get__cos_zDiff(el);
24
+ cg->jaws_parallel = BlackAbsorberData_get__jaws_parallel(el);
25
+ // Tilts
26
+ cg->sin_yL = BlackAbsorberData_get__sin_yL(el);
27
+ cg->cos_yL = BlackAbsorberData_get__cos_yL(el);
28
+ cg->sin_yR = BlackAbsorberData_get__sin_yR(el);
29
+ cg->cos_yR = BlackAbsorberData_get__cos_yR(el);
30
+ // Length and segments
31
+ cg->length = BlackAbsorberData_get_length(el);
32
+ cg->side = BlackAbsorberData_get__side(el);
33
+ double s_U, s_D, x_D;
34
+ if (cg->side != -1){
35
+ s_U = cg->length/2 * (1-cg->cos_yL);
36
+ s_D = cg->length/2 * (1+cg->cos_yL);
37
+ x_D = BlackAbsorberData_get__jaw_LD(el);
38
+ cg->segments_L = create_jaw(s_U, cg->jaw_LU, s_D, x_D, cg->sin_yL/cg->cos_yL, 1);
39
+ }
40
+ if (cg->side != 1){
41
+ s_U = cg->length/2 * (1-cg->cos_yR);
42
+ s_D = cg->length/2 * (1+cg->cos_yR);
43
+ x_D = BlackAbsorberData_get__jaw_RD(el);
44
+ cg->segments_R = create_jaw(s_U, cg->jaw_RU, s_D, x_D, cg->sin_yR/cg->cos_yR, -1);
45
+ }
46
+ // Impact table
47
+ cg->record = BlackAbsorberData_getp_internal_record(el, part0);
48
+ cg->record_index = NULL;
49
+ cg->record_touches = 0;
50
+ if (cg->record){
51
+ cg->record_index = InteractionRecordData_getp__index(cg->record);
52
+ cg->record_touches = BlackAbsorberData_get_record_touches(el);
53
+ }
54
+ }
55
+
56
+ return cg;
57
+ }
58
+
59
+ /*gpufun*/
60
+ void BlackAbsorber_free(CollimatorGeometry restrict cg, int8_t active){
61
+ if (active){
62
+ if (cg->side != -1){
63
+ destroy_jaw(cg->segments_L);
64
+ }
65
+ if (cg->side != 1){
66
+ destroy_jaw(cg->segments_R);
67
+ }
68
+ }
69
+ free(cg);
70
+ }
71
+
72
+
73
+ /*gpufun*/
74
+ void BlackAbsorber_track_local_particle(BlackAbsorberData el, LocalParticle* part0){
75
+
76
+ // Collimator active and length
77
+ int8_t active = BlackAbsorberData_get_active(el);
78
+ active *= BlackAbsorberData_get__tracking(el);
79
+ double const length = BlackAbsorberData_get_length(el);
80
+
81
+ // Get geometry
82
+ CollimatorGeometry cg = BlackAbsorber_init_geometry(el, part0, active);
83
+ int8_t record_scatterings = BlackAbsorberData_get_record_scatterings(el);
84
+
85
+ //start_per_particle_block (part0->part)
86
+ if (!active){
87
+ // Drift full length
88
+ Drift_single_particle(part, length);
89
+
90
+ } else {
91
+ // Check collimator initialisation
92
+ int8_t is_tracking = assert_tracking(part, XC_ERR_INVALID_TRACK);
93
+
94
+ if (is_tracking) {
95
+ // Store s-location of start of collimator
96
+ double s_coll = LocalParticle_get_s(part);
97
+ LocalParticle_set_s(part, 0);
98
+
99
+ // Check if hit on jaws
100
+ int8_t is_hit = hit_jaws_check_and_transform(part, cg);
101
+
102
+ if (is_hit != 0){
103
+ LocalParticle_set_state(part, XC_LOST_ON_ABSORBER);
104
+ if (record_scatterings) {
105
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_ABSORBED); // In coll jaw reference frame
106
+ }
107
+ }
108
+
109
+ // Transform back to the lab frame
110
+ hit_jaws_transform_back(is_hit, part, cg);
111
+ LocalParticle_add_to_s(part, s_coll);
112
+ }
113
+ }
114
+ //end_per_particle_block
115
+ BlackAbsorber_free(cg, active);
116
+ }
117
+
118
+ #endif /* XCOLL_COLL_GEOM_H */
@@ -0,0 +1,111 @@
1
+ // copyright ############################### #
2
+ // This file is part of the Xcoll Package. #
3
+ // Copyright (c) CERN, 2024. #
4
+ // ######################################### #
5
+
6
+ #ifndef XCOLL_ABSORBER_CRY_H
7
+ #define XCOLL_ABSORBER_CRY_H
8
+
9
+
10
+ /*gpufun*/
11
+ CrystalGeometry BlackCrystal_init_geometry(BlackCrystalData el, LocalParticle* part0, int8_t active){
12
+ CrystalGeometry cg = (CrystalGeometry) malloc(sizeof(CrystalGeometry_));
13
+ if (active){ // This is needed in order to avoid that the initialisation is called during a twiss!
14
+ cg->length = BlackCrystalData_get_length(el);
15
+ cg->side = BlackCrystalData_get__side(el);
16
+ cg->bending_radius = BlackCrystalData_get__bending_radius(el);
17
+ cg->bending_angle = BlackCrystalData_get__bending_angle(el);
18
+ cg->width = BlackCrystalData_get_width(el);
19
+ cg->height = BlackCrystalData_get_height(el);
20
+ cg->jaw_U = BlackCrystalData_get__jaw_U(el);
21
+ cg->sin_z = BlackCrystalData_get__sin_z(el);
22
+ cg->cos_z = BlackCrystalData_get__cos_z(el);
23
+ cg->sin_y = BlackCrystalData_get__sin_y(el);
24
+ cg->cos_y = BlackCrystalData_get__cos_y(el);
25
+ double jaw;
26
+ if (cg->side == 1){
27
+ jaw = cg->jaw_U;
28
+ } else if (cg->side == -1){
29
+ jaw = cg->jaw_U - cg->width; // To ensure that jaw_U is the inner corner
30
+ } else {
31
+ kill_all_particles(part0, XC_ERR_INVALID_XOFIELD);
32
+ return cg;
33
+ }
34
+ cg->segments = create_crystal(cg->bending_radius, cg->width, cg->length, jaw, cg->sin_y, cg->cos_y);
35
+ // Impact table
36
+ cg->record = BlackCrystalData_getp_internal_record(el, part0);
37
+ cg->record_index = NULL;
38
+ cg->record_touches = 0;
39
+ if (cg->record){
40
+ cg->record_index = InteractionRecordData_getp__index(cg->record);
41
+ cg->record_touches = BlackCrystalData_get_record_touches(el);
42
+ }
43
+ // Not needed, set to zero
44
+ cg->miscut_angle = 0;
45
+ cg->s_P = 0;
46
+ cg->x_P = 0;
47
+ cg->t_VImax = 0;
48
+ }
49
+
50
+ return cg;
51
+ }
52
+
53
+ /*gpufun*/
54
+ void BlackCrystal_free(CrystalGeometry restrict cg, int8_t active){
55
+ if (active){
56
+ destroy_crystal(cg->segments);
57
+ }
58
+ free(cg);
59
+ }
60
+
61
+
62
+ /*gpufun*/
63
+ void BlackCrystal_track_local_particle(BlackCrystalData el, LocalParticle* part0){
64
+
65
+ // Collimator active and length
66
+ int8_t active = BlackCrystalData_get_active(el);
67
+ active *= BlackCrystalData_get__tracking(el);
68
+ double const length = BlackCrystalData_get_length(el);
69
+
70
+ // Get geometry
71
+ CrystalGeometry cg = BlackCrystal_init_geometry(el, part0, active);
72
+ int8_t record_scatterings = BlackCrystalData_get_record_scatterings(el);
73
+
74
+ if (cg->width==0 || cg->height==0 || cg->bending_radius==0){
75
+ kill_all_particles(part0, XC_ERR_INVALID_XOFIELD);
76
+ }
77
+
78
+ //start_per_particle_block (part0->part)
79
+ if (!active){
80
+ // Drift full length
81
+ Drift_single_particle(part, length);
82
+
83
+ } else {
84
+ // Check collimator initialisation
85
+ int8_t is_tracking = assert_tracking(part, XC_ERR_INVALID_TRACK);
86
+
87
+ if (is_tracking) {
88
+ // Store s-location of start of collimator
89
+ double s_coll = LocalParticle_get_s(part);
90
+ LocalParticle_set_s(part, 0);
91
+
92
+ // Check if hit on jaws
93
+ int8_t is_hit = hit_crystal_check_and_transform(part, cg);
94
+
95
+ if (is_hit != 0){
96
+ LocalParticle_set_state(part, XC_LOST_ON_ABSORBER);
97
+ if (record_scatterings) {
98
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_ABSORBED); // In coll jaw reference frame
99
+ }
100
+ }
101
+
102
+ // Transform back to the lab frame
103
+ hit_crystal_transform_back(is_hit, part, cg);
104
+ LocalParticle_add_to_s(part, s_coll);
105
+ }
106
+ }
107
+ //end_per_particle_block
108
+ BlackCrystal_free(cg, active);
109
+ }
110
+
111
+ #endif /* XCOLL_ABSORBER_CRY_H */
@@ -39,7 +39,7 @@ EverestCollData EverestBlock_init(EverestBlockData el, LocalParticle* part0, int
39
39
  coll->record = EverestBlockData_getp_internal_record(el, part0);
40
40
  coll->record_index = NULL;
41
41
  if (coll->record){
42
- coll->record_index = CollimatorImpactsData_getp__index(coll->record);
42
+ coll->record_index = InteractionRecordData_getp__index(coll->record);
43
43
  }
44
44
  }
45
45
 
@@ -84,43 +84,55 @@ void EverestBlock_track_local_particle(EverestBlockData el, LocalParticle* part0
84
84
  int8_t is_valid = xcoll_check_particle_init(coll->rng, part);
85
85
 
86
86
  if (is_valid) {
87
- EverestData everest = EverestBlock_init_data(part, coll);
88
- double const e0 = LocalParticle_get_energy0(part) / 1.e9; // Reference energy in GeV
89
- double const p0 = LocalParticle_get_p0c(part) / 1e9; // Reference momentum in GeV
87
+ // Store s-location of start of block
88
+ double s_block = LocalParticle_get_s(part);
89
+ LocalParticle_set_s(part, 0);
90
+
91
+ // Store initial coordinates for updating later
92
+ double const e0 = LocalParticle_get_energy0(part);
93
+ double const p0 = LocalParticle_get_p0c(part);
94
+ double const ptau_in = LocalParticle_get_ptau(part);
95
+ double const rvv_in = LocalParticle_get_rvv(part);
96
+ #ifdef XCOLL_USE_EXACT
97
+ double const xp_in = LocalParticle_get_exact_xp(part);
98
+ double const yp_in = LocalParticle_get_exact_yp(part);
99
+ #else
100
+ double const xp_in = LocalParticle_get_xp(part);
101
+ double const yp_in = LocalParticle_get_yp(part);
102
+ #endif
103
+ double const zeta_in = LocalParticle_get_zeta(part);
90
104
  double const mass_ratio = LocalParticle_get_charge_ratio(part) / LocalParticle_get_chi(part); // m/m0
91
- double energy = (LocalParticle_get_ptau(part)*p0 + e0) * mass_ratio; // energy in GeV
92
- int is_abs = 0;
93
- double const rpp_in = LocalParticle_get_rpp(part);
94
- double const rvv_in = LocalParticle_get_rvv(part);
95
- double const px_in = LocalParticle_get_px(part);
96
- double const py_in = LocalParticle_get_py(part);
97
-
98
- double* result = jaw(everest, part, energy, length, 0);
99
- energy = result[0];
100
- if (result[1] == 1){ is_abs = 1; }
101
- double s_out = result[2];
102
- free(result);
105
+ double energy = (p0*ptau_in + e0) * mass_ratio;
106
+
107
+ EverestData everest = EverestBlock_init_data(part, coll);
108
+ energy = jaw(everest, part, energy, length, 0);
103
109
  free(everest);
104
110
 
105
- double ptau_out = (energy/mass_ratio - e0) / p0;
106
- LocalParticle_update_ptau(part, ptau_out);
107
- if (is_abs==0){
108
- double px = LocalParticle_get_px(part);
109
- double py = LocalParticle_get_py(part);
111
+ LocalParticle_add_to_s(part, s_block);
112
+
113
+ LocalParticle_set_zeta(part, zeta_in);
114
+ // Survived particles need correcting:
115
+ if (LocalParticle_get_state(part)>0){
116
+ // Update energy
117
+ double ptau_out = (energy/mass_ratio - e0) / p0;
118
+ LocalParticle_update_ptau(part, ptau_out);
119
+ // Update zeta
120
+ #ifdef XCOLL_USE_EXACT
121
+ double xp = LocalParticle_get_exact_xp(part);
122
+ double yp = LocalParticle_get_exact_yp(part);
123
+ #else
124
+ double xp = LocalParticle_get_xp(part);
125
+ double yp = LocalParticle_get_yp(part);
126
+ #endif
110
127
  double rvv = LocalParticle_get_rvv(part);
111
- double rpp = LocalParticle_get_rpp(part);
112
128
  // First we drift half the length with the old angles:
113
- LocalParticle_add_to_zeta(part, drift_zeta_single(rvv_in, px_in*rpp_in, py_in*rpp_in, length/2) );
129
+ LocalParticle_add_to_zeta(part, drift_zeta_single(rvv_in, xp_in, yp_in, length/2) );
114
130
  // then half the length with the new angles:
115
- LocalParticle_add_to_zeta(part, drift_zeta_single(rvv, px*rpp, py*rpp, length/2) );
116
- } else {
117
- LocalParticle_set_s(part, s_out);
118
- LocalParticle_set_state(part, XC_LOST_ON_EVEREST_BLOCK);
131
+ LocalParticle_add_to_zeta(part, drift_zeta_single(rvv, xp, yp, length/2) );
119
132
  }
120
133
  }
121
134
  }
122
135
  //end_per_particle_block
123
-
124
136
  free(coll);
125
137
  }
126
138
 
@@ -1,6 +1,6 @@
1
1
  // copyright ############################### #
2
2
  // This file is part of the Xcoll Package. #
3
- // Copyright (c) CERN, 2023. #
3
+ // Copyright (c) CERN, 2024. #
4
4
  // ######################################### #
5
5
 
6
6
  #ifndef XCOLL_EVEREST_COLL_H
@@ -16,6 +16,69 @@ void EverestCollimator_set_material(EverestCollimatorData el){
16
16
  }
17
17
 
18
18
 
19
+ /*gpufun*/
20
+ CollimatorGeometry EverestCollimator_init_geometry(EverestCollimatorData el, LocalParticle* part0, int8_t active){
21
+ CollimatorGeometry cg = (CollimatorGeometry) malloc(sizeof(CollimatorGeometry_));
22
+ if (active){ // This is needed in order to avoid that the initialisation is called during a twiss!
23
+ // Jaw corners (with tilts)
24
+ cg->jaw_LU = EverestCollimatorData_get__jaw_LU(el);
25
+ cg->jaw_RU = EverestCollimatorData_get__jaw_RU(el);
26
+ // Get angles of jaws
27
+ cg->sin_zL = EverestCollimatorData_get__sin_zL(el);
28
+ cg->cos_zL = EverestCollimatorData_get__cos_zL(el);
29
+ cg->sin_zR = EverestCollimatorData_get__sin_zR(el);
30
+ cg->cos_zR = EverestCollimatorData_get__cos_zR(el);
31
+ cg->sin_zDiff = EverestCollimatorData_get__sin_zDiff(el);
32
+ cg->cos_zDiff = EverestCollimatorData_get__cos_zDiff(el);
33
+ cg->jaws_parallel = EverestCollimatorData_get__jaws_parallel(el);
34
+ // Tilts
35
+ cg->sin_yL = EverestCollimatorData_get__sin_yL(el);
36
+ cg->cos_yL = EverestCollimatorData_get__cos_yL(el);
37
+ cg->sin_yR = EverestCollimatorData_get__sin_yR(el);
38
+ cg->cos_yR = EverestCollimatorData_get__cos_yR(el);
39
+ // Length and segments
40
+ cg->length = EverestCollimatorData_get_length(el);
41
+ cg->side = EverestCollimatorData_get__side(el);
42
+ double s_U, s_D, x_D;
43
+ if (cg->side != -1){
44
+ s_U = cg->length/2 * (1-cg->cos_yL);
45
+ s_D = cg->length/2 * (1+cg->cos_yL);
46
+ x_D = EverestCollimatorData_get__jaw_LD(el);
47
+ cg->segments_L = create_jaw(s_U, cg->jaw_LU, s_D, x_D, cg->sin_yL/cg->cos_yL, 1);
48
+ }
49
+ if (cg->side != 1){
50
+ s_U = cg->length/2 * (1-cg->cos_yR);
51
+ s_D = cg->length/2 * (1+cg->cos_yR);
52
+ x_D = EverestCollimatorData_get__jaw_RD(el);
53
+ cg->segments_R = create_jaw(s_U, cg->jaw_RU, s_D, x_D, cg->sin_yR/cg->cos_yR, -1);
54
+ }
55
+ // Impact table
56
+ cg->record = EverestCollimatorData_getp_internal_record(el, part0);
57
+ cg->record_index = NULL;
58
+ cg->record_touches = 0;
59
+ if (cg->record){
60
+ cg->record_index = InteractionRecordData_getp__index(cg->record);
61
+ cg->record_touches = EverestCollimatorData_get_record_touches(el);
62
+ }
63
+ }
64
+
65
+ return cg;
66
+ }
67
+
68
+ /*gpufun*/
69
+ void EverestCollimator_free(CollimatorGeometry restrict cg, int8_t active){
70
+ if (active){
71
+ if (cg->side != -1){
72
+ destroy_jaw(cg->segments_L);
73
+ }
74
+ if (cg->side != 1){
75
+ destroy_jaw(cg->segments_R);
76
+ }
77
+ }
78
+ free(cg);
79
+ }
80
+
81
+
19
82
  // TODO: it would be great if we could set EverestData as an xofield, because then we could
20
83
  // run this function at creation of the collimator instead of every turn
21
84
  // Hmmmm this should be called whenever we change an xofield
@@ -36,21 +99,15 @@ EverestCollData EverestCollimator_init(EverestCollimatorData el, LocalParticle*
36
99
  coll->csref[1] = MaterialData_get_cross_section(material, 1);
37
100
  coll->csref[5] = MaterialData_get_cross_section(material, 5);
38
101
  coll->only_mcs = MaterialData_get__only_mcs(material);
39
-
40
- // Impact table
102
+ // Impact table: need it here to record interactions
41
103
  coll->record = EverestCollimatorData_getp_internal_record(el, part0);
42
104
  coll->record_index = NULL;
105
+ coll->record_scatterings = 0;
43
106
  if (coll->record){
44
- coll->record_index = CollimatorImpactsData_getp__index(coll->record);
107
+ coll->record_index = InteractionRecordData_getp__index(coll->record);
108
+ coll->record_scatterings = EverestCollimatorData_get_record_scatterings(el);
109
+ coll->record_touches = EverestCollimatorData_get_record_touches(el);
45
110
  }
46
-
47
- // Geometry
48
- // TODO: this should in principle not be in this struct
49
- coll->aperture = EverestCollimatorData_get_jaw_L(el) - EverestCollimatorData_get_jaw_R(el);
50
- coll->offset = ( EverestCollimatorData_get_jaw_L(el) + EverestCollimatorData_get_jaw_R(el) ) /2;
51
- coll->tilt_L = asin(EverestCollimatorData_get_sin_yL(el));
52
- coll->tilt_R = asin(EverestCollimatorData_get_sin_yR(el));
53
- coll->side = EverestCollimatorData_get__side(el);
54
111
  }
55
112
 
56
113
  return coll;
@@ -80,63 +137,85 @@ EverestData EverestCollimator_init_data(LocalParticle* part, EverestCollData col
80
137
  void EverestCollimator_track_local_particle(EverestCollimatorData el, LocalParticle* part0) {
81
138
  int8_t active = EverestCollimatorData_get_active(el);
82
139
  active *= EverestCollimatorData_get__tracking(el);
83
- double const inactive_front = EverestCollimatorData_get_inactive_front(el);
84
- double const active_length = EverestCollimatorData_get_active_length(el);
85
- double const inactive_back = EverestCollimatorData_get_inactive_back(el);
86
-
87
- // Collimator geometry
88
- double const co_x = EverestCollimatorData_get_ref_x(el);
89
- double const co_y = EverestCollimatorData_get_ref_y(el);
90
- // TODO: we are ignoring the angle of the right jaw
91
- double const sin_zL = EverestCollimatorData_get_sin_zL(el);
92
- double const cos_zL = EverestCollimatorData_get_cos_zL(el);
93
- double const sin_zR = EverestCollimatorData_get_sin_zR(el);
94
- double const cos_zR = EverestCollimatorData_get_cos_zR(el);
95
- if (fabs(sin_zL-sin_zR) > 1.e-10 || fabs(cos_zL-cos_zR) > 1.e-10 ){
96
- printf("Jaws with different angles not yet implemented!"); //only_for_context cpu_serial
97
- fflush(stdout); //only_for_context cpu_serial
98
- kill_all_particles(part0, XC_ERR_NOT_IMPLEMENTED);
99
- };
140
+ double const length = EverestCollimatorData_get_length(el);
100
141
 
101
142
  // Initialise collimator data
102
143
  // TODO: we want this to happen before tracking (instead of every turn), as a separate kernel
103
- EverestCollData coll = EverestCollimator_init(el, part0, active);
144
+ EverestCollData coll = EverestCollimator_init(el, part0, active);
145
+ CollimatorGeometry cg = EverestCollimator_init_geometry(el, part0, active);
104
146
 
105
147
  //start_per_particle_block (part0->part)
106
148
  if (!active){
107
149
  // Drift full length
108
- Drift_single_particle(part, inactive_front + active_length + inactive_back);
150
+ Drift_single_particle(part, length);
109
151
 
110
152
  } else {
111
153
  // Check collimator initialisation
112
154
  int8_t is_valid = xcoll_check_particle_init(coll->rng, part);
113
155
 
114
156
  if (is_valid) {
115
- // Drift inactive front
116
- Drift_single_particle(part, inactive_front);
117
-
118
- // Move to collimator frame
119
- XYShift_single_particle(part, co_x, co_y);
120
- SRotation_single_particle(part, sin_zL, cos_zL);
121
-
122
- EverestData everest = EverestCollimator_init_data(part, coll);
123
- scatter(everest, part, active_length);
124
- free(everest);
125
-
126
- // Return from collimator frame
127
- SRotation_single_particle(part, -sin_zL, cos_zL);
128
- XYShift_single_particle(part, -co_x, -co_y);
157
+ // Store s-location of start of collimator
158
+ double const s_coll = LocalParticle_get_s(part);
159
+ LocalParticle_set_s(part, 0);
160
+
161
+ // Store initial coordinates for updating later
162
+ double const e0 = LocalParticle_get_energy0(part);
163
+ double const p0 = LocalParticle_get_p0c(part);
164
+ double const ptau_in = LocalParticle_get_ptau(part);
165
+ double const rvv_in = LocalParticle_get_rvv(part);
166
+ #ifdef XCOLL_USE_EXACT
167
+ double const xp_in = LocalParticle_get_exact_xp(part);
168
+ double const yp_in = LocalParticle_get_exact_yp(part);
169
+ #else
170
+ double const xp_in = LocalParticle_get_xp(part);
171
+ double const yp_in = LocalParticle_get_yp(part);
172
+ #endif
173
+ double const zeta_in = LocalParticle_get_zeta(part);
174
+ double const mass_ratio = LocalParticle_get_charge_ratio(part) / LocalParticle_get_chi(part); // m/m0
175
+ double energy = (p0*ptau_in + e0) * mass_ratio;
176
+
177
+ // Check if hit on jaws
178
+ int8_t is_hit = hit_jaws_check_and_transform(part, cg);
179
+
180
+ if (is_hit != 0) {
181
+ // Hit one of the jaws, so scatter
182
+ double remaining_length = length - LocalParticle_get_s(part);
183
+ // Scatter
184
+ EverestData everest = EverestCollimator_init_data(part, coll);
185
+ energy = jaw(everest, part, energy, remaining_length, 1);
186
+ free(everest);
187
+ }
129
188
 
130
- // Drift inactive back (only surviving particles)
131
- if (LocalParticle_get_state(part) > 0){
132
- Drift_single_particle(part, inactive_back);
189
+ // Transform back to the lab frame
190
+ hit_jaws_transform_back(is_hit, part, cg);
191
+ LocalParticle_add_to_s(part, s_coll);
192
+
193
+ LocalParticle_set_zeta(part, zeta_in);
194
+ // Hit and survived particles need correcting:
195
+ if (is_hit!=0 && LocalParticle_get_state(part)>0){
196
+ // Update energy
197
+ double ptau_out = (energy/mass_ratio - e0) / p0;
198
+ LocalParticle_update_ptau(part, ptau_out);
199
+ // Update zeta
200
+ #ifdef XCOLL_USE_EXACT
201
+ double xp = LocalParticle_get_exact_xp(part);
202
+ double yp = LocalParticle_get_exact_yp(part);
203
+ #else
204
+ double xp = LocalParticle_get_xp(part);
205
+ double yp = LocalParticle_get_yp(part);
206
+ #endif
207
+ double rvv = LocalParticle_get_rvv(part);
208
+ // First we drift half the length with the old angles:
209
+ LocalParticle_add_to_zeta(part, drift_zeta_single(rvv_in, xp_in, yp_in, length/2) );
210
+ // then half the length with the new angles:
211
+ LocalParticle_add_to_zeta(part, drift_zeta_single(rvv, xp, yp, length/2) );
133
212
  }
134
213
  }
135
214
  }
136
215
  //end_per_particle_block
137
-
216
+ EverestCollimator_free(cg, active);
138
217
  free(coll);
139
218
  }
140
219
 
141
220
 
142
- #endif /* XCOLL_EVEREST_COLL_H */
221
+ #endif /* XCOLL_EVEREST_COLL_H */