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
@@ -1,34 +1,20 @@
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_ENGINE_H
7
7
  #define XCOLL_EVEREST_ENGINE_H
8
8
 
9
+ #define XCOLL_TRANSITION
9
10
 
10
11
  typedef struct EverestCollData_ {
11
12
  // Collimator properties
12
- double aperture; // TODO: This should go out, as it's geometry and that should not be used in Everest scattering
13
- double offset; // TODO: This should go out, as it's geometry and that should not be used in Everest scattering
14
- double tilt_L; // TODO: This should go out, as it's geometry and that should not be used in Everest scattering
15
- double tilt_R; // TODO: This should go out, as it's geometry and that should not be used in Everest scattering
16
- double side; // TODO: This should go out, as it's geometry and that should not be used in Everest scattering
17
13
  RandomRutherfordData restrict rng;
18
- CollimatorImpactsData record;
14
+ InteractionRecordData record;
19
15
  RecordIndex record_index;
20
- // Crystal properties
21
- double bend_r;
22
- double bend_ang;
23
- double tilt;
24
- double amorphous_layer;
25
- double xdim;
26
- double ydim;
27
- int8_t orient;
28
- double miscut;
29
- double s_P;
30
- double x_P;
31
- double t_VImax;
16
+ int8_t record_scatterings;
17
+ int8_t record_touches;
32
18
  // Material properties
33
19
  // TODO: can we use pointers for the MaterialData? It then gets a bit difficult to read them, ie *coll->exenergy
34
20
  double exenergy;
@@ -43,6 +29,8 @@ typedef struct EverestCollData_ {
43
29
  double ai;
44
30
  double eum;
45
31
  double collnt;
32
+ double eta;
33
+ int8_t orient;
46
34
  int8_t only_mcs;
47
35
  } EverestCollData_;
48
36
  typedef EverestCollData_ *EverestCollData;
@@ -62,6 +50,7 @@ typedef struct EverestData_ {
62
50
  double prob_tail_c4;
63
51
  double energy_loss;
64
52
  double energy_loss_tail;
53
+ // Crystal data
65
54
  double rescale_scattering;
66
55
  double t_c;
67
56
  double t_c0;
@@ -90,17 +79,6 @@ void Drift_single_particle_4d(LocalParticle* part, double length){
90
79
  LocalParticle_set_zeta(part, zeta);
91
80
  }
92
81
 
93
- /*gpufun*/
94
- double YRotation_single_particle_rotate_only(LocalParticle* part, double s, double angle){
95
- double x = LocalParticle_get_x(part);
96
- double rpp = LocalParticle_get_rpp(part);
97
- double sin_y = sin(angle);
98
- double cos_y = cos(angle);
99
- LocalParticle_set_x(part, x*cos_y - s*sin_y);
100
- LocalParticle_add_to_px(part,-angle/rpp);
101
- return x*sin_y + s*cos_y; // new s
102
- }
103
-
104
82
  /*gpukern*/
105
83
  void RandomRutherford_set_by_xcoll_material(RandomRutherfordData ran, GeneralMaterialData material){
106
84
  double const zatom = GeneralMaterialData_get_Z(material);
@@ -1,30 +1,33 @@
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
- import xobjects as xo
7
6
  import xtrack as xt
8
7
 
9
8
  from .materials import Material, CrystalMaterial
10
- from ...impacts import CollimatorImpacts
9
+ from ..geometry import XcollGeometry
10
+ from ...interaction_record import InteractionRecord
11
11
  from ...general import _pkg_root
12
12
 
13
13
 
14
- class EverestEngine(xo.HybridClass):
14
+ class EverestEngine(xt.BeamElement):
15
15
  _xofields = {}
16
16
 
17
- _depends_on = [Material, CrystalMaterial, CollimatorImpacts, xt.RandomUniform, xt.RandomExponential,
18
- xt.RandomNormal, xt.RandomRutherford, xt.Drift]
17
+ allow_track = False
18
+
19
+ _depends_on = [Material, CrystalMaterial, InteractionRecord, xt.RandomUniform, xt.RandomExponential,
20
+ xt.RandomNormal, xt.RandomRutherford, xt.Drift, XcollGeometry]
19
21
 
20
22
  _extra_c_sources = [
23
+ _pkg_root.joinpath('scattering_routines','geometry','rotation.h'),
21
24
  _pkg_root.joinpath('scattering_routines','everest','constants.h'),
22
25
  _pkg_root.joinpath('scattering_routines','everest','everest.h'),
23
26
  _pkg_root.joinpath('scattering_routines','everest','properties.h'),
24
- # _pkg_root.joinpath('scattering_routines','everest','scatter_init.h'),
25
27
  _pkg_root.joinpath('scattering_routines','everest','multiple_coulomb_scattering.h'),
28
+ _pkg_root.joinpath('scattering_routines','everest','nuclear_interaction.h'),
29
+ _pkg_root.joinpath('scattering_routines','everest','crystal_parameters.h'),
30
+ _pkg_root.joinpath('scattering_routines','everest','amorphous.h'),
26
31
  _pkg_root.joinpath('scattering_routines','everest','jaw.h'),
27
- _pkg_root.joinpath('scattering_routines','everest','scatter.h'),
28
- _pkg_root.joinpath('scattering_routines','everest','crystal.h'),
29
- _pkg_root.joinpath('scattering_routines','everest','scatter_crystal.h')
32
+ _pkg_root.joinpath('scattering_routines','everest','channeling.h')
30
33
  ]
@@ -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_JAW_H
@@ -9,227 +9,57 @@
9
9
  #include <stdio.h>
10
10
 
11
11
 
12
-
13
12
  /*gpufun*/
14
- double* tetat(LocalParticle* part, double t, double p) {
15
- double teta = sqrt(t)/p;
16
- double va = 0;
17
- double vb = 0;
18
- double va2 = 0;
19
- double vb2 = 0;
20
- double r2 = 0;
21
- double* result = (double*)malloc(2 * sizeof(double));
22
-
23
- while (1) {
24
- va = 2*RandomUniform_generate(part) - 1;
25
- vb = RandomUniform_generate(part);
26
- va2 = pow(va,2);
27
- vb2 = pow(vb,2);
28
- r2 = va2 + vb2;
29
- if(r2 < 1) {
30
- break;
31
- }
13
+ double jaw(EverestData restrict everest, LocalParticle* part, double p, double length, int edge_check) {
14
+ if (LocalParticle_get_state(part) < 1){
15
+ // Do nothing if already absorbed
16
+ return p;
32
17
  }
33
-
34
- result[0] = (teta*((2*va)*vb))/r2;
35
- result[1] = (teta*(va2 - vb2))/r2;
36
- return result;
37
- }
38
-
39
-
40
- /*gpufun*/
41
- double* gettran(EverestData restrict everest, LocalParticle* part, double inter, double p) {
42
-
43
- double* res = (double*)malloc(2 * sizeof(double));
44
-
45
- // Neither if-statements below have an else, so defaulting function return to zero.
46
- double result = 0;
47
-
48
- if (inter==2) { // Nuclear Elastic
49
- result = RandomExponential_generate(part)/everest->bn;
50
-
51
- } else if (inter==3) { // pp Elastic
52
- result = RandomExponential_generate(part)/everest->bpp;
53
-
54
- } else if (inter==4) { // Single Diffractive
55
- double xm2 = exp(RandomUniform_generate(part) * everest->xln15s);
56
- double bsd = 0;
57
- p = p * (1 - xm2/everest->ecmsq);
58
-
59
- if (xm2 < 2) {
60
- bsd = 2 * everest->bpp;
61
- } else if ((xm2 >= 2) & (xm2 <= 5)) {
62
- bsd = ((106.0 - 17.0*xm2)*everest->bpp)/36.0;
63
- } else {
64
- bsd = (7*everest->bpp)/12.0;
65
- }
66
- result = RandomExponential_generate(part)/bsd;
67
-
68
- } else if (inter==5) { // Coulomb
69
- result = RandomRutherford_generate(everest->coll->rng, part);
70
- }
71
-
72
- res[0] = result;
73
- res[1] = p;
74
- return res;
75
- }
76
-
77
-
78
- /*gpufun*/
79
- int ichoix(EverestData restrict everest, LocalParticle* part) {
80
-
81
- double aran = RandomUniform_generate(part);
82
- int i;
83
- for (i = 0; i < 5; ++i) {
84
- if (aran < everest->cprob[i]) {
85
- break;
86
- }
87
- }
88
- return i;
89
- }
90
18
 
91
-
92
- /*gpufun*/
93
- double* jaw(EverestData restrict everest, LocalParticle* part, double p, double zlm, int edge_check) {
94
-
95
- double* result = (double*)malloc(3 * sizeof(double));
96
-
97
- double s;
98
- double nabs = 0;
99
- double rlen = zlm;
100
- double m_dpodx = 0.;
101
- double t;
102
- double tx;
103
- double tz;
104
-
105
- double rpp_in = LocalParticle_get_rpp(part);
106
- double x = LocalParticle_get_x(part);
107
- double xp = LocalParticle_get_px(part)*rpp_in;
108
- double z = LocalParticle_get_y(part);
109
- double zp = LocalParticle_get_py(part)*rpp_in;
19
+ double rlen = length;
20
+ double s0 = LocalParticle_get_s(part);
21
+ p /= 1e9; // Energy (not momentum) in GeV
110
22
 
111
23
  if (everest->coll->only_mcs) {
112
- double* res = mcs(everest, part, zlm, p, x, xp, z, zp, edge_check);
113
- s = res[0];
114
- x = res[1];
115
- xp = res[2];
116
- z = res[3];
117
- zp = res[4];
118
- free(res);
24
+ mcs(everest, part, rlen, p, edge_check);
119
25
 
120
26
  } else {
121
27
  // Do a step for a point-like interaction.
122
28
  // Get monte-carlo interaction length.
123
29
  while (1) {
124
-
125
30
  calculate_ionisation_properties(everest, p);
126
- double zlm1 = everest->xintl*RandomExponential_generate(part);
31
+ double length_step = everest->xintl*RandomExponential_generate(part);
127
32
 
128
- // If the monte-carlo interaction length is longer than the
129
- // remaining collimator length, then put it to the remaining
130
- // length, do multiple coulomb scattering and return.
131
- // LAST STEP IN ITERATION LOOP
132
- if (zlm1 > rlen) {
133
- zlm1 = rlen;
134
- double* res = mcs(everest, part, zlm1, p, x, xp, z, zp, edge_check);
135
- s = res[0];
136
- x = res[1];
137
- xp = res[2];
138
- z = res[3];
139
- zp = res[4];
140
- free(res);
141
-
142
- s = zlm - rlen + s;
143
- m_dpodx = calcionloss(everest, part, rlen); // DM routine to include tail // TODO: should not be rlen but s after updating
144
- p = p-m_dpodx*s; // This is correct: ionisation loss is only calculated and applied at end of while (break)
33
+ // If the monte-carlo interaction length is longer than the remaining
34
+ // length, then put it to the remaining length, do mcs and return.
35
+ if (length_step > rlen) {
36
+ mcs(everest, part, rlen, p, edge_check);
145
37
  break;
146
38
  }
147
- // Otherwise do multi-coulomb scattering.
148
- // REGULAR STEP IN ITERATION LOOP
149
- double* res1 = mcs(everest, part, zlm1, p, x, xp, z, zp, edge_check);
150
- s = res1[0];
151
- x = res1[1];
152
- xp = res1[2];
153
- z = res1[3];
154
- zp = res1[4];
155
- free(res1);
156
39
 
157
- // Check if particle is outside of collimator (X.LT.0) after
158
- // MCS. If yes, calculate output longitudinal position (s),
159
- // reduce momentum (output as dpop) and return.
160
- // PARTICLE LEFT COLLIMATOR BEFORE ITS END.
40
+ // Otherwise do multi-coulomb scattering.
41
+ mcs(everest, part, length_step, p, edge_check);
161
42
 
162
- if(x <= 0) {
163
- s = zlm - rlen + s;
164
- m_dpodx = calcionloss(everest, part, rlen); // TODO: should not be rlen but s after updating
165
- p = p-m_dpodx*s; // correct
43
+ if(LocalParticle_get_x(part) <= 0) {
44
+ // PARTICLE LEFT COLLIMATOR BEFORE ITS END.
166
45
  break;
167
46
  }
168
47
 
169
- // Check whether particle is absorbed. If yes, calculate output
170
- // longitudinal position (s), reduce momentum (output as dpop)
171
- // and return.
172
- // PARTICLE WAS ABSORBED INSIDE COLLIMATOR DURING MCS.
173
-
174
- int inter = ichoix(everest, part);
175
- nabs = inter;
176
- if (inter == 1) {
177
- s = zlm - rlen + zlm1;
178
- m_dpodx = calcionloss(everest, part, rlen);
179
- p = p-m_dpodx*s;
48
+ p = nuclear_interaction(everest, part, p);
49
+ if (LocalParticle_get_state(part) < 1){
50
+ // PARTICLE WAS ABSORBED INSIDE COLLIMATOR DURING MCS.
180
51
  break;
181
52
  }
182
53
 
183
-
184
- // Now treat the other types of interaction, as determined by ICHOIX:
185
-
186
- // Nuclear-Elastic: inter = 2
187
- // pp Elastic: inter = 3
188
- // Single-Diffractive: inter = 4 (changes momentum p)
189
- // Coulomb: inter = 5
190
-
191
- // Gettran returns some monte carlo number, that, as I believe, gives the rms transverse momentum transfer.
192
-
193
- double* res2 = gettran(everest, part, inter, p);
194
- t = res2[0];
195
- p = res2[1];
196
- free(res2);
197
-
198
- // Tetat calculates from the rms transverse momentum transfer in
199
- // monte-carlo fashion the angle changes for x and z planes. The
200
- // angle change is proportional to SQRT(t) and 1/p, as expected.
201
-
202
- double* res3 = tetat(part, t, p);
203
- tx = res3[0];
204
- tz = res3[1];
205
- free(res3);
206
-
207
- // Apply angle changes
208
- xp = xp + tx;
209
- zp = zp + tz;
210
-
211
- // Treat single-diffractive scattering. TODO: this does nothing??
212
- if(inter == 4) {
213
- // added update for s
214
- s = zlm - rlen + zlm1;
215
- }
216
-
217
54
  // Calculate the remaining interaction length and close the iteration loop.
218
- rlen = rlen - zlm1;
55
+ rlen = rlen - length_step;
219
56
  }
220
57
  }
58
+ double m_dpodx = calcionloss(everest, part, rlen); // DM routine to include tail // TODO: should not be rlen but s after updating
59
+ double s = LocalParticle_get_s(part) - s0;
60
+ p = p-m_dpodx*s; // TODO: This is correct: ionisation loss is only calculated and applied at end of while (break)
221
61
 
222
- LocalParticle_set_x(part, x);
223
- LocalParticle_set_px(part, xp/rpp_in);
224
- LocalParticle_set_y(part, z);
225
- LocalParticle_set_py(part, zp/rpp_in);
226
- LocalParticle_add_to_s(part, s); // TODO: is this correct with tilt etc?
227
-
228
- result[0] = p;
229
- result[1] = nabs;
230
- result[2] = s;
231
- return result;
232
- }
233
-
62
+ return p*1e9; // Back to eV
63
+ }
234
64
 
235
65
  #endif /* XCOLL_EVEREST_JAW_H */
@@ -18,6 +18,8 @@ import xobjects as xo
18
18
  # as xobjects enforces a strict order: static fields first, and then dynamic fields.
19
19
  # See struct.py, in __new__ of MetaStruct
20
20
 
21
+ # A HybridClass needs something to depend on, otherwise the class is added twice in the cdefs during compilation
22
+
21
23
  class GeneralMaterial(xo.HybridClass):
22
24
  _xofields = {
23
25
  'Z': xo.Float64, # zatom
@@ -80,7 +80,7 @@ double soln3(double a, double b, double dh, double smax) {
80
80
  /*gpufun*/
81
81
  double* scamcs(LocalParticle* part, double x0, double xp0, double s) {
82
82
  double* result = (double*)malloc(2 * sizeof(double));
83
-
83
+
84
84
  // Generate two Gaussian random numbers z1 and z2
85
85
  double r2 = 0;
86
86
  double v1 = 0;
@@ -107,7 +107,14 @@ double* scamcs(LocalParticle* part, double x0, double xp0, double s) {
107
107
 
108
108
 
109
109
  /*gpufun*/
110
- double* mcs(EverestData restrict everest, LocalParticle* part, double zlm1, double p, double x, double xp, double z, double zp, int edge_check) {
110
+ void mcs(EverestData restrict everest, LocalParticle* part, double length, double p, int edge_check){
111
+ InteractionRecordData record = everest->coll->record;
112
+ RecordIndex record_index = everest->coll->record_index;
113
+ int8_t sc = everest->coll->record_scatterings;
114
+
115
+ // First log particle at start of multiple coulomb scattering
116
+ int64_t i_slot;
117
+ if (sc) i_slot = InteractionRecordData_log(record, record_index, part, XC_MULTIPLE_COULOMB_SCATTERING);
111
118
 
112
119
  double const radl = everest->coll->radl;
113
120
  double s;
@@ -115,9 +122,18 @@ double* mcs(EverestData restrict everest, LocalParticle* part, double zlm1, doub
115
122
  double h = 0.001;
116
123
  double dh = 0.0001;
117
124
  double bn0 = 0.4330127019;
118
- double rlen0 = zlm1/radl;
125
+ double rlen0 = length/radl;
119
126
  double rlen = rlen0;
120
- double* result = (double*)malloc(5 * sizeof(double));
127
+
128
+ double x = LocalParticle_get_x(part);
129
+ double z = LocalParticle_get_y(part);
130
+ #ifdef XCOLL_USE_EXACT
131
+ double xp = LocalParticle_get_exact_xp(part); // This is tangent
132
+ double zp = LocalParticle_get_exact_yp(part); // This is tangent
133
+ #else
134
+ double xp = LocalParticle_get_xp(part);
135
+ double zp = LocalParticle_get_yp(part);
136
+ #endif
121
137
 
122
138
  x = (x/theta)/radl;
123
139
  xp = xp/theta;
@@ -169,12 +185,17 @@ double* mcs(EverestData restrict everest, LocalParticle* part, double zlm1, doub
169
185
  zp = res[1];
170
186
  free(res);
171
187
 
172
- result[0] = s*radl;
173
- result[1] = (x*theta)*radl;
174
- result[2] = xp*theta;
175
- result[3] = (z*theta)*radl;
176
- result[4] = zp*theta;
177
- return result;
188
+ LocalParticle_set_x(part, x*theta*radl);
189
+ LocalParticle_set_y(part, z*theta*radl);
190
+ #ifdef XCOLL_USE_EXACT
191
+ LocalParticle_set_exact_xp_yp(part, xp*theta, zp*theta);
192
+ #else
193
+ LocalParticle_set_xp_yp(part, xp*theta, zp*theta);
194
+ #endif
195
+ LocalParticle_add_to_s(part, s*radl);
196
+
197
+ // Finally log particle at end of multiple coulomb scattering
198
+ if (sc) InteractionRecordData_log_child(record, i_slot, part, length);
178
199
  }
179
200
 
180
201
  #endif /* XCOLL_EVEREST_MCS_H */
@@ -0,0 +1,86 @@
1
+ // copyright ############################### #
2
+ // This file is part of the Xcoll Package. #
3
+ // Copyright (c) CERN, 2024. #
4
+ // ######################################### #
5
+
6
+ #ifndef XCOLL_EVEREST_NUCL_H
7
+ #define XCOLL_EVEREST_NUCL_H
8
+ #include <math.h>
9
+ #include <stdio.h>
10
+
11
+
12
+ /*gpufun*/
13
+ double nuclear_interaction(EverestData restrict everest, LocalParticle* part, double pc) {
14
+ InteractionRecordData record = everest->coll->record;
15
+ RecordIndex record_index = everest->coll->record_index;
16
+ int8_t sc = everest->coll->record_scatterings;
17
+
18
+ #ifdef XCOLL_REFINE_ENERGY
19
+ calculate_scattering(everest, pc);
20
+ #endif
21
+
22
+ //Choose nuclear interaction
23
+ double aran = RandomUniform_generate(part);
24
+ int ichoix = 1;
25
+
26
+ while (aran > everest->cprob[ichoix]) {
27
+ ichoix += 1;
28
+ }
29
+
30
+ //Do the interaction
31
+ int64_t i_slot = -1;
32
+ if (ichoix==1) {
33
+ if (sc) i_slot = InteractionRecordData_log(record, record_index, part, XC_ABSORBED);
34
+ LocalParticle_set_state(part, XC_LOST_ON_EVEREST_COLL);
35
+
36
+ } else {
37
+ double teta;
38
+ if (ichoix==2) { // p-n elastic
39
+ if (sc) i_slot = InteractionRecordData_log(record, record_index, part, XC_PN_ELASTIC);
40
+ teta = sqrt(RandomExponential_generate(part)/everest->bn)/pc;
41
+
42
+ } else if (ichoix==3) { // p-p elastic
43
+ if (sc) i_slot = InteractionRecordData_log(record, record_index, part, XC_PP_ELASTIC);
44
+ teta = sqrt(RandomExponential_generate(part)/everest->bpp)/pc;
45
+
46
+ } else if (ichoix==4) { // Single diffractive
47
+ if (sc) i_slot = InteractionRecordData_log(record, record_index, part, XC_SINGLE_DIFFRACTIVE);
48
+ double xm2 = exp(RandomUniform_generate(part)*everest->xln15s);
49
+ double bsd;
50
+ if (xm2 < 2.) {
51
+ bsd = 2*everest->bpp;
52
+ } else if (xm2 >= 2. && xm2 <= 5.) {
53
+ bsd = ((106.0 - 17.0*xm2)*everest->bpp)/36.0;
54
+ } else {
55
+ bsd = (7*everest->bpp)/12.0;
56
+ }
57
+ double pc_in = pc;
58
+ pc = pc*(1 - xm2/everest->ecmsq);
59
+ // Corrected 1/p into 1/sqrt(pp')
60
+ teta = sqrt(RandomExponential_generate(part)/bsd)/sqrt(pc_in*pc);
61
+
62
+ } else { // Coulomb
63
+ if (sc) i_slot = InteractionRecordData_log(record, record_index, part, XC_COULOMB);
64
+ teta = sqrt(RandomRutherford_generate(everest->coll->rng, part))/pc;
65
+ }
66
+
67
+ // TODO: I am not convinced that we can just sample two independent random numbers
68
+ // I believe it should be tan(tx) = cos(phi) * tan(teta) and tan(ty) = sin(phi) * tan(teta)
69
+ // with phi uniformly sampled between 0 and 2 pi
70
+ double tx = teta*RandomNormal_generate(part);
71
+ double tz = teta*RandomNormal_generate(part);
72
+
73
+ //Change the angles
74
+ #ifdef XCOLL_USE_EXACT
75
+ LocalParticle_add_to_exact_xp_yp(part, tx, tz);
76
+ #else
77
+ LocalParticle_add_to_xp_yp(part, tx, tz);
78
+ #endif
79
+
80
+ if (sc) InteractionRecordData_log_child(record, i_slot, part, 0);
81
+ }
82
+
83
+ return pc;
84
+ }
85
+
86
+ #endif /* XCOLL_EVEREST_NUCL_H */
@@ -0,0 +1,6 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll Package. #
3
+ # Copyright (c) CERN, 2024. #
4
+ # ######################################### #
5
+
6
+ from .geometry import XcollGeometry