xcoll 0.3.6__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.6.dist-info → xcoll-0.4.0.dist-info}/METADATA +1 -1
  45. {xcoll-0.3.6.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.6.dist-info → xcoll-0.4.0.dist-info}/LICENSE +0 -0
  55. {xcoll-0.3.6.dist-info → xcoll-0.4.0.dist-info}/NOTICE +0 -0
  56. {xcoll-0.3.6.dist-info → xcoll-0.4.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,219 @@
1
+ // copyright ############################### #
2
+ // This file is part of the Xcoll Package. #
3
+ // Copyright (c) CERN, 2024. #
4
+ // ######################################### #
5
+
6
+ #ifndef XCOLL_COLL_GEOM_H
7
+ #define XCOLL_COLL_GEOM_H
8
+ #include <math.h>
9
+ #include <stdio.h>
10
+
11
+ typedef struct CollimatorGeometry_ {
12
+ // Collimator jaws (with tilts)
13
+ double jaw_LU;
14
+ double jaw_RU;
15
+ double length;
16
+ int8_t side;
17
+ // Jaw angles
18
+ double sin_zL;
19
+ double cos_zL;
20
+ double sin_zR;
21
+ double cos_zR;
22
+ double sin_zDiff;
23
+ double cos_zDiff;
24
+ int8_t jaws_parallel;
25
+ // Tilts
26
+ double sin_yL;
27
+ double cos_yL;
28
+ double sin_yR;
29
+ double cos_yR;
30
+ // Segments
31
+ Segment* segments_L;
32
+ Segment* segments_R;
33
+ // Impact table
34
+ InteractionRecordData record;
35
+ RecordIndex record_index;
36
+ int8_t record_touches;
37
+ } CollimatorGeometry_;
38
+ typedef CollimatorGeometry_* CollimatorGeometry;
39
+
40
+
41
+ // This function checks if a particle hits a jaw (and which).
42
+ // Return value: 0 (no hit), 1 (hit on left jaw), -1 (hit on right jaw).
43
+ // Furthermore, the particle is moved to the location where it hits the jaw (drifted to the end if no hit),
44
+ // and transformed to the reference frame of that jaw.
45
+ /*gpufun*/
46
+ int8_t hit_jaws_check_and_transform(LocalParticle* part, CollimatorGeometry restrict cg){
47
+ double part_x, part_tan;
48
+ int8_t is_hit = 0;
49
+ double s_L = 1.e21;
50
+ double s_R = 1.e21;
51
+
52
+ // Find the first hit on the left jaw (if not a right-sided collimator)
53
+ if (cg->side != -1){
54
+ SRotation_single_particle(part, cg->sin_zL, cg->cos_zL);
55
+ part_x = LocalParticle_get_x(part);
56
+ #ifdef XCOLL_USE_EXACT
57
+ part_tan = LocalParticle_get_exact_xp(part);
58
+ #else
59
+ part_tan = LocalParticle_get_xp(part);
60
+ #endif
61
+ s_L = get_s_of_first_crossing(part_x, part_tan, cg->segments_L, 3);
62
+ if (s_L < S_MAX){
63
+ is_hit = 1;
64
+ } else if (cg->side == 1){
65
+ // If left-sided and no hit, rotate back to lab frame
66
+ SRotation_single_particle(part, -cg->sin_zL, cg->cos_zL);
67
+ }
68
+ }
69
+
70
+ // if rightsided: lab frame
71
+ // if leftsided and no hit: lab frame
72
+ // if leftsided and hit: left frame
73
+ // if bothsided and no hit: left frame
74
+ // if bothsided and hit: left frame
75
+
76
+ // Find the first hit on the right jaw (if not a left-sided collimator)
77
+ if (cg->side != 1){
78
+ if (cg->side == -1){
79
+ // We didn't rotate to the left frame earlier, so full rotation to the right frame now
80
+ SRotation_single_particle(part, cg->sin_zR, cg->cos_zR);
81
+ } else if (!cg->jaws_parallel){
82
+ // We rotated to the left frame before, so now rotate the difference
83
+ SRotation_single_particle(part, cg->sin_zDiff, cg->cos_zDiff);
84
+ }
85
+ part_x = LocalParticle_get_x(part);
86
+ #ifdef XCOLL_USE_EXACT
87
+ part_tan = LocalParticle_get_exact_xp(part);
88
+ #else
89
+ part_tan = LocalParticle_get_xp(part);
90
+ #endif
91
+ s_R = get_s_of_first_crossing(part_x, part_tan, cg->segments_R, 3);
92
+ if (s_R < S_MAX && s_R < s_L){
93
+ is_hit = -1;
94
+ } else if (is_hit == 1){
95
+ if (!cg->jaws_parallel){
96
+ // Rotate back to left frame
97
+ SRotation_single_particle(part, -cg->sin_zDiff, cg->cos_zDiff);
98
+ }
99
+ } else {
100
+ // No hit, rotate back to lab frame
101
+ SRotation_single_particle(part, -cg->sin_zR, cg->cos_zR);
102
+ }
103
+ }
104
+
105
+ // if rightsided and no hit: lab frame
106
+ // if rightsided and hit: right frame
107
+ // if leftsided and no hit: lab frame
108
+ // if leftsided and hit: left frame
109
+ // if bothsided and no hit: lab frame
110
+ // if bothsided and hit: hit frame
111
+
112
+
113
+ // Drift to the impact position or end, and move to jaw frame if relevant
114
+ if (is_hit == 1){
115
+ // Move to the impact position
116
+ #ifdef XCOLL_USE_EXACT
117
+ Drift_single_particle_exact(part, s_L);
118
+ #else
119
+ Drift_single_particle_expanded(part, s_L);
120
+ #endif
121
+ // Shift the reference frame to the jaw corner LU
122
+ XYShift_single_particle(part, cg->jaw_LU, 0);
123
+ LocalParticle_add_to_s(part, -cg->length/2*(1 - cg->cos_yL));
124
+ // Rotate the reference frame to tilt
125
+ double new_s = YRotation_single_particle_rotate_only(part, LocalParticle_get_s(part), asin(cg->sin_yL));
126
+ LocalParticle_set_s(part, new_s);
127
+ if (cg->record_touches){
128
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_ENTER_JAW_L);
129
+ }
130
+
131
+ } else if (is_hit == -1){
132
+ // Move to the impact position
133
+ #ifdef XCOLL_USE_EXACT
134
+ Drift_single_particle_exact(part, s_R);
135
+ #else
136
+ Drift_single_particle_expanded(part, s_R);
137
+ #endif
138
+ // Shift the reference frame to the jaw corner RU
139
+ XYShift_single_particle(part, cg->jaw_RU, 0);
140
+ LocalParticle_add_to_s(part, -cg->length/2*(1 - cg->cos_yR));
141
+ // Rotate the reference frame to tilt
142
+ double new_s = YRotation_single_particle_rotate_only(part, LocalParticle_get_s(part), asin(cg->sin_yR));
143
+ LocalParticle_set_s(part, new_s);
144
+ // Mirror x
145
+ LocalParticle_scale_x(part, -1);
146
+ #ifdef XCOLL_USE_EXACT
147
+ LocalParticle_scale_exact_xp(part, -1);
148
+ #else
149
+ LocalParticle_scale_xp(part, -1);
150
+ #endif
151
+ if (cg->record_touches){
152
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_ENTER_JAW_R);
153
+ }
154
+
155
+ } else {
156
+ #ifdef XCOLL_USE_EXACT
157
+ Drift_single_particle_exact(part, cg->length);
158
+ #else
159
+ Drift_single_particle_expanded(part, cg->length);
160
+ #endif
161
+ }
162
+
163
+ return is_hit;
164
+ }
165
+
166
+
167
+ /*gpufun*/
168
+ void hit_jaws_transform_back(int8_t is_hit, LocalParticle* part, CollimatorGeometry restrict cg){
169
+ if (is_hit == 1){
170
+ // Rotate back from tilt
171
+ double new_s = YRotation_single_particle_rotate_only(part, LocalParticle_get_s(part), -asin(cg->sin_yL));
172
+ LocalParticle_set_s(part, new_s);
173
+ // Shift the reference frame back from jaw corner LU
174
+ XYShift_single_particle(part, -cg->jaw_LU, 0);
175
+ LocalParticle_add_to_s(part, cg->length/2*(1 - cg->cos_yL));
176
+ // If particle survived, drift to end of element
177
+ if (LocalParticle_get_state(part) > 0){
178
+ if (cg->record_touches){
179
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_EXIT_JAW);
180
+ }
181
+ #ifdef XCOLL_USE_EXACT
182
+ Drift_single_particle_exact(part, cg->length - LocalParticle_get_s(part));
183
+ #else
184
+ Drift_single_particle_expanded(part, cg->length - LocalParticle_get_s(part));
185
+ #endif
186
+ }
187
+ SRotation_single_particle(part, -cg->sin_zL, cg->cos_zL);
188
+
189
+ } else if (is_hit == -1){
190
+ // Mirror back
191
+ LocalParticle_scale_x(part, -1);
192
+ #ifdef XCOLL_USE_EXACT
193
+ LocalParticle_scale_exact_xp(part, -1);
194
+ #else
195
+ LocalParticle_scale_xp(part, -1);
196
+ #endif
197
+ // Rotate back from tilt
198
+ double new_s = YRotation_single_particle_rotate_only(part, LocalParticle_get_s(part), -asin(cg->sin_yR));
199
+ LocalParticle_set_s(part, new_s);
200
+ // Shift the reference frame back from jaw corner RU
201
+ XYShift_single_particle(part, -cg->jaw_RU, 0);
202
+ LocalParticle_add_to_s(part, cg->length/2*(1 - cg->cos_yR));
203
+ // If particle survived, drift to end of element
204
+ if (LocalParticle_get_state(part) > 0){
205
+ if (cg->record_touches){
206
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_EXIT_JAW);
207
+ }
208
+ #ifdef XCOLL_USE_EXACT
209
+ Drift_single_particle_exact(part, cg->length - LocalParticle_get_s(part));
210
+ #else
211
+ Drift_single_particle_expanded(part, cg->length - LocalParticle_get_s(part));
212
+ #endif
213
+ }
214
+ SRotation_single_particle(part, -cg->sin_zR, cg->cos_zR);
215
+ }
216
+ }
217
+
218
+
219
+ #endif /* XCOLL_COLL_GEOM_H */
@@ -0,0 +1,150 @@
1
+ // copyright ############################### #
2
+ // This file is part of the Xcoll Package. #
3
+ // Copyright (c) CERN, 2024. #
4
+ // ######################################### #
5
+
6
+ #ifndef XCOLL_CRY_GEOM_H
7
+ #define XCOLL_CRY_GEOM_H
8
+ #include <math.h>
9
+ #include <stdio.h>
10
+
11
+ typedef struct CrystalGeometry_ {
12
+ // Crystal inner upstream corner (with tilt)
13
+ double jaw_U;
14
+ double length;
15
+ int8_t side;
16
+ // Jaw angle
17
+ double sin_z;
18
+ double cos_z;
19
+ // Tilt
20
+ double sin_y;
21
+ double cos_y;
22
+ // Crystal geometry
23
+ double bending_radius;
24
+ double bending_angle;
25
+ double width;
26
+ double height;
27
+ double miscut_angle;
28
+ double s_B; // Bend centre
29
+ double x_B;
30
+ double s_P; // Miscut centre
31
+ double x_P;
32
+ double t_VImax;
33
+ // Segments
34
+ Segment* segments;
35
+ // Impact table
36
+ InteractionRecordData record;
37
+ RecordIndex record_index;
38
+ int8_t record_touches;
39
+ } CrystalGeometry_;
40
+ typedef CrystalGeometry_* CrystalGeometry;
41
+
42
+
43
+ // This function checks if a particle hits a jaw (and which).
44
+ // Return value: 0 (no hit), 1 (hit on left jaw), -1 (hit on right jaw).
45
+ // Furthermore, the particle is moved to the location where it hits the jaw (drifted to the end if no hit),
46
+ // and transformed to the reference frame of that jaw.
47
+ /*gpufun*/
48
+ int8_t hit_crystal_check_and_transform(LocalParticle* part, CrystalGeometry restrict cg){
49
+ double part_x, part_tan_x, part_y, part_tan_y;
50
+ double s = 1.e21;
51
+
52
+ // Crystal should be single-sided
53
+ if (cg->side == 0){
54
+ LocalParticle_kill_particle(part, XC_ERR_NOT_IMPLEMENTED);
55
+ }
56
+
57
+ SRotation_single_particle(part, cg->sin_z, cg->cos_z);
58
+ part_x = LocalParticle_get_x(part);
59
+ #ifdef XCOLL_USE_EXACT
60
+ part_tan_x = LocalParticle_get_exact_xp(part);
61
+ #else
62
+ part_tan_x = LocalParticle_get_xp(part);
63
+ #endif
64
+ part_y = LocalParticle_get_y(part);
65
+ #ifdef XCOLL_USE_EXACT
66
+ part_tan_y = LocalParticle_get_exact_yp(part);
67
+ #else
68
+ part_tan_y = LocalParticle_get_yp(part);
69
+ #endif
70
+ s = get_s_of_first_crossing_with_vlimit(part_x, part_tan_x, part_y, part_tan_y, cg->segments, 4, -cg->height/2, cg->height/2);
71
+
72
+ if (s < S_MAX){
73
+ // Hit: Drift to the impact position, and move to jaw frame if relevant
74
+ #ifdef XCOLL_USE_EXACT
75
+ Drift_single_particle_exact(part, s);
76
+ #else
77
+ Drift_single_particle_expanded(part, s);
78
+ #endif
79
+ // Shift the reference frame to the upstream jaw corner (for a crystal, this is always at s=0)
80
+ XYShift_single_particle(part, cg->jaw_U, 0);
81
+ // Rotate the reference frame to tilt
82
+ double new_s = YRotation_single_particle_rotate_only(part, LocalParticle_get_s(part), asin(cg->sin_y));
83
+ LocalParticle_set_s(part, new_s);
84
+ if (cg->side == 1){
85
+ if (cg->record_touches){
86
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_ENTER_JAW_L);
87
+ }
88
+
89
+ } else {
90
+ // Mirror x
91
+ LocalParticle_scale_x(part, -1);
92
+ #ifdef XCOLL_USE_EXACT
93
+ LocalParticle_scale_exact_xp(part, -1);
94
+ #else
95
+ LocalParticle_scale_xp(part, -1);
96
+ #endif
97
+ if (cg->record_touches){
98
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_ENTER_JAW_R);
99
+ }
100
+ }
101
+ return cg->side;
102
+
103
+ } else {
104
+ // No hit, rotate back to lab frame
105
+ SRotation_single_particle(part, -cg->sin_z, cg->cos_z);
106
+ // Drift to end
107
+ #ifdef XCOLL_USE_EXACT
108
+ Drift_single_particle_exact(part, cg->length);
109
+ #else
110
+ Drift_single_particle_expanded(part, cg->length);
111
+ #endif
112
+ return 0;
113
+ }
114
+ }
115
+
116
+
117
+ /*gpufun*/
118
+ void hit_crystal_transform_back(int8_t is_hit, LocalParticle* part, CrystalGeometry restrict cg){
119
+ if (is_hit != 0){
120
+ if (cg->side == -1){
121
+ // Mirror back
122
+ LocalParticle_scale_x(part, -1);
123
+ #ifdef XCOLL_USE_EXACT
124
+ LocalParticle_scale_exact_xp(part, -1);
125
+ #else
126
+ LocalParticle_scale_xp(part, -1);
127
+ #endif
128
+ }
129
+ // Rotate back from tilt
130
+ double new_s = YRotation_single_particle_rotate_only(part, LocalParticle_get_s(part), -asin(cg->sin_y));
131
+ LocalParticle_set_s(part, new_s);
132
+ // Shift the reference frame back from jaw corner U
133
+ XYShift_single_particle(part, -cg->jaw_U, 0);
134
+ // If particle survived, drift to end of element
135
+ if (LocalParticle_get_state(part) > 0){
136
+ if (cg->record_touches){
137
+ InteractionRecordData_log(cg->record, cg->record_index, part, XC_EXIT_JAW);
138
+ }
139
+ #ifdef XCOLL_USE_EXACT
140
+ Drift_single_particle_exact(part, cg->length - LocalParticle_get_s(part));
141
+ #else
142
+ Drift_single_particle_expanded(part, cg->length - LocalParticle_get_s(part));
143
+ #endif
144
+ }
145
+ SRotation_single_particle(part, -cg->sin_z, cg->cos_z);
146
+ }
147
+ }
148
+
149
+
150
+ #endif /* XCOLL_CRY_GEOM_H */
@@ -0,0 +1,26 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll Package. #
3
+ # Copyright (c) CERN, 2024. #
4
+ # ######################################### #
5
+
6
+ import xtrack as xt
7
+ from ...interaction_record import InteractionRecord
8
+ from ...general import _pkg_root
9
+
10
+ class XcollGeometry(xt.BeamElement):
11
+ _xofields = {}
12
+
13
+ allow_track = False
14
+
15
+ _depends_on = [xt.Drift, xt.XYShift, xt.SRotation, xt.YRotation, InteractionRecord]
16
+
17
+ _extra_c_sources = [
18
+ _pkg_root.joinpath('scattering_routines','geometry','sort.h'),
19
+ _pkg_root.joinpath('scattering_routines','geometry','segments.h'),
20
+ _pkg_root.joinpath('scattering_routines','geometry','objects.h'),
21
+ _pkg_root.joinpath('scattering_routines','geometry','methods.h'),
22
+ _pkg_root.joinpath('scattering_routines','geometry','get_s.h'),
23
+ _pkg_root.joinpath('scattering_routines','geometry','rotation.h'),
24
+ _pkg_root.joinpath('scattering_routines','geometry','collimator_geometry.h'),
25
+ _pkg_root.joinpath('scattering_routines','geometry','crystal_geometry.h')
26
+ ]
@@ -0,0 +1,92 @@
1
+ // copyright ############################### #
2
+ // This file is part of the Xcoll Package. #
3
+ // Copyright (c) CERN, 2024. #
4
+ // ######################################### #
5
+
6
+ #ifndef XCOLL_GEOM_GET_S_H
7
+ #define XCOLL_GEOM_GET_S_H
8
+ #include <math.h>
9
+ #include <stdio.h>
10
+ #include <stdint.h>
11
+ #include <stdlib.h>
12
+
13
+
14
+ // IMPORTANT:
15
+ // These functions assume that the particle moves towards positive s!
16
+ // (hence no backscattering/backtracking is allowed)
17
+
18
+
19
+ /*gpufun*/
20
+ double get_s_of_first_crossing(double part_x, double part_tan, Segment* segments, \
21
+ int8_t n_segments){
22
+ int8_t n_hit = 0;
23
+ double* s = (double*) malloc(XC_MAX_CROSS_PER_SEGMENT*n_segments*sizeof(double));
24
+ find_crossing(&n_hit, s, part_x, part_tan, segments, n_segments);
25
+ if (n_hit==0){
26
+ // No crossing
27
+ free(s);
28
+ return S_MAX;
29
+ }
30
+ double result = s[0];
31
+ free(s);
32
+ return result;
33
+ }
34
+
35
+ /*gpufun*/
36
+ double get_s_of_crossing_after_s(double part_x, double part_tan, Segment* segments, \
37
+ int8_t n_segments, double current_s){
38
+ int8_t n_hit = 0;
39
+ double* s = (double*) malloc(XC_MAX_CROSS_PER_SEGMENT*n_segments*sizeof(double));
40
+ find_crossing(&n_hit, s, part_x, part_tan, segments, n_segments);
41
+ for (int8_t i=0; i<n_hit; i++){
42
+ if (s[i] >= current_s){
43
+ double result = s[i];
44
+ free(s);
45
+ return result;
46
+ }
47
+ }
48
+ // No crossing
49
+ free(s);
50
+ return S_MAX;
51
+ }
52
+
53
+ /*gpufun*/
54
+ double get_s_of_first_crossing_with_vlimit(double part_x, double part_tan_x, \
55
+ double part_y, double part_tan_y, Segment* segments, \
56
+ int8_t n_segments, double y_min, double y_max){
57
+ int8_t n_hit = 0;
58
+ double* s = (double*) malloc(XC_MAX_CROSS_PER_SEGMENT*n_segments*sizeof(double));
59
+ find_crossing_with_vlimit(&n_hit, s, part_x, part_tan_x, part_y, part_tan_y, \
60
+ segments, n_segments, y_min, y_max);
61
+ if (n_hit==0){
62
+ // No crossing
63
+ free(s);
64
+ return S_MAX;
65
+ }
66
+ double result = s[0];
67
+ free(s);
68
+ return result;
69
+ }
70
+
71
+ /*gpufun*/
72
+ double get_s_of_crossing_after_s_with_vlimit(double part_x, double part_tan_x, \
73
+ double part_y, double part_tan_y, Segment* segments, \
74
+ int8_t n_segments, double y_min, double y_max, double current_s){
75
+ int8_t n_hit = 0;
76
+ double* s = (double*) malloc(XC_MAX_CROSS_PER_SEGMENT*n_segments*sizeof(double));
77
+ find_crossing_with_vlimit(&n_hit, s, part_x, part_tan_x, part_y, part_tan_y, \
78
+ segments, n_segments, y_min, y_max);
79
+ for (int8_t i=0; i<n_hit; i++){
80
+ if (s[i] >= current_s){
81
+ double result = s[i];
82
+ free(s);
83
+ return result;
84
+ }
85
+ }
86
+ // No crossing
87
+ free(s);
88
+ return S_MAX;
89
+ }
90
+
91
+
92
+ #endif /* XCOLL_GEOM_GET_S_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_GEOM_METHODS_H
7
+ #define XCOLL_GEOM_METHODS_H
8
+ #include <math.h>
9
+ #include <stdio.h>
10
+ #include <stdint.h>
11
+ #include <stdlib.h>
12
+
13
+ #define S_MAX 1.e21
14
+
15
+
16
+ /*gpufun*/
17
+ void find_crossing(int8_t* n_hit, double* s, double part_x, double part_tan, \
18
+ Segment* segments, int8_t n_segments){
19
+ for (int8_t i=0; i<n_segments;i++) {
20
+ segments[i]->crossing(n_hit, s, part_x, part_tan, segments[i]);
21
+ }
22
+ sort_array_of_double(s, (int64_t) *n_hit);
23
+ }
24
+
25
+
26
+ // IMPORTANT:
27
+ // The array and interval are assumed to be sorted!
28
+ // Furthermore, the array should have one extra slot allocated at the end, in case it needs to be expanded..
29
+ // This is always true for the arrays created by get_s, as we create them with 2*n_segments slots.
30
+ /*gpufun*/
31
+ void calculate_overlap_array_interval(double* arr, int8_t* length, double* interval){
32
+ if (arr[0] > interval[1]){
33
+ // No overlap
34
+ *length = 0;
35
+ }
36
+ if ((*length)%2 == 1){
37
+ // Special case: last interval of array is open until infinity,
38
+ // so we add an extra point at the end to represent infinity.
39
+ arr[*length] = S_MAX*0.1;
40
+ (*length)++;
41
+ } else if (arr[*length-1] < interval[0]){
42
+ // No overlap
43
+ *length = 0;
44
+ }
45
+ int8_t i_start = 0;
46
+ // Find the start of overlap
47
+ for (int8_t i=0; i<*length; i++){
48
+ if (arr[i] >= interval[0]){
49
+ if (i%2 == 0){
50
+ // This is the first point of overlap
51
+ i_start = i;
52
+ } else {
53
+ // The vertical restriction is the first point of overlap
54
+ i_start = i-1;
55
+ arr[i_start] = interval[0];
56
+ }
57
+ break;
58
+ }
59
+ }
60
+ // Find the end of overlap
61
+ int8_t i_stop = *length - 1;
62
+ for (int8_t i=0; i<*length; i++){
63
+ if (arr[i] >= interval[1]){
64
+ if (i%2 == 0){
65
+ // The previous point is the last point of overlap
66
+ i_stop = i-1;
67
+ } else {
68
+ // The vertical restriction is the first point of overlap
69
+ i_stop = i;
70
+ arr[i_stop] = interval[1];
71
+ }
72
+ break;
73
+ }
74
+ }
75
+ *length = i_stop - i_start + 1;
76
+ if (i_start > 0){
77
+ for (int8_t i=0; i<*length; i++){
78
+ arr[i] = arr[i+i_start];
79
+ }
80
+ }
81
+ }
82
+
83
+
84
+ /*gpufun*/
85
+ void find_crossing_with_vlimit(int8_t* n_hit, double* s, double part_x, double part_tan_x, \
86
+ double part_y, double part_tan_y, Segment* segments, \
87
+ int8_t n_segments, double y_min, double y_max){
88
+ if (fabs(part_tan_y) < 1.e-12){
89
+ // Trajectory parallel to s axis
90
+ if (part_y < y_min || part_y > y_max){
91
+ // No crossing
92
+ return;
93
+ } else {
94
+ // The particle is completely inside the vertical limits, so only check horizontal
95
+ find_crossing(n_hit, s, part_x, part_tan_x, segments, n_segments);
96
+ return;
97
+ }
98
+ } else {
99
+ find_crossing(n_hit, s, part_x, part_tan_x, segments, n_segments);
100
+ // restrict_s is the region [s0, s1] where the particle is inside the vertical limits
101
+ double* restrict_s = (double*) malloc(2*sizeof(double));
102
+ restrict_s[0] = (y_min - part_y)/part_tan_y;
103
+ restrict_s[1] = (y_max - part_y)/part_tan_y;
104
+ SWAP(restrict_s, 0, 1); // To make sure these are sorted
105
+ calculate_overlap_array_interval(s, n_hit, restrict_s);
106
+ free(restrict_s);
107
+ }
108
+ }
109
+
110
+
111
+ #endif /* XCOLL_GEOM_METHODS_H */