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
@@ -1,1302 +0,0 @@
1
- // copyright ############################### #
2
- // This file is part of the Xcoll Package. #
3
- // Copyright (c) CERN, 2023. #
4
- // ######################################### #
5
-
6
- #ifndef XCOLL_EVEREST_CRYSTAL_INTERACT_H
7
- #define XCOLL_EVEREST_CRYSTAL_INTERACT_H
8
- #include <math.h>
9
- #include <stdio.h>
10
- #include <stdlib.h>
11
-
12
- double const tlcut_cry = 0.0009982;
13
-
14
- double const aTF = 0.194e-10; // Screening function [m]
15
- double const dP = 1.920e-10; // Distance between planes (110) [m]
16
- double const u1 = 0.075e-10; // Thermal vibrations amplitude
17
-
18
- // pp cross-sections and parameters for energy dependence
19
- double const pptref_cry = 0.040;
20
- double const freeco_cry = 1.618;
21
-
22
- // Processes
23
- int const proc_out = -1; // Crystal not hit
24
- int const proc_AM = 1; // Amorphous
25
- int const proc_VR = 2; // Volume reflection
26
- int const proc_CH = 3; // Channeling
27
- int const proc_VC = 4; // Volume capture
28
- int const proc_absorbed = 5; // Absorption
29
- int const proc_DC = 6; // Dechanneling
30
- int const proc_pne = 7; // Proton-neutron elastic interaction
31
- int const proc_ppe = 8; // Proton-proton elastic interaction
32
- int const proc_diff = 9; // Single diffractive
33
- int const proc_ruth = 10; // Rutherford scattering
34
- int const proc_ch_absorbed = 15; // Channeling followed by absorption
35
- int const proc_ch_pne = 17; // Channeling followed by proton-neutron elastic interaction
36
- int const proc_ch_ppe = 18; // Channeling followed by proton-proton elastic interaction
37
- int const proc_ch_diff = 19; // Channeling followed by single diffractive
38
- int const proc_ch_ruth = 20; // Channeling followed by Rutherford scattering
39
- int const proc_TRVR = 100; // Volume reflection in VR-AM transition region
40
- int const proc_TRAM = 101; // Amorphous in VR-AM transition region
41
-
42
-
43
- /*gpufun*/
44
- double* movech(RandomRutherfordData rng, LocalParticle* part, double nam, double dz, double x, double xp, double yp, double pc, double r, double rc, double rho, double anuc, double zatom, double emr, double hcut, double bnref, double csref0, double csref1, double csref5, double eUm, double collnt, double iProc) {
45
-
46
- double* result = (double*)malloc(5 * sizeof(double));
47
-
48
- // // Material properties
49
- // double const exenergy = CrystalMaterialData_get_excitation_energy(material);
50
- // double const rho = CrystalMaterialData_get_density(material);
51
- // double const anuc = CrystalMaterialData_get_A(material);
52
- // double const zatom = CrystalMaterialData_get_Z(material);
53
- // double const emr = CrystalMaterialData_get_nuclear_radius(material);
54
- // double const dlri = CrystalMaterialData_get_crystal_radiation_length(material);
55
- // double const dlyi = CrystalMaterialData_get_crystal_nuclear_length(material);
56
- // double const ai = CrystalMaterialData_get_crystal_plane_distance(material);
57
- // double const eum = CrystalMaterialData_get_crystal_potential(material);
58
- // double const collnt = CrystalMaterialData_get_nuclear_collision_length(material);
59
- // double const hcut = CrystalMaterialData_get_hcut(material);
60
- // double const bnref = CrystalMaterialData_get_nuclear_elastic_slope(material);
61
- // double const csref0 = CrystalMaterialData_get_cross_section(material, 0);
62
- // double const csref1 = CrystalMaterialData_get_cross_section(material, 1);
63
- // double const csref5 = CrystalMaterialData_get_cross_section(material, 5);
64
-
65
- double pmap = 938.271998;
66
- double pc_in = pc;
67
-
68
- double cs[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
69
- double cprob[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
70
- double xran_cry[1] = {0.0};
71
-
72
- //New treatment of scattering routine based on standard sixtrack routine
73
-
74
- //Useful calculations for cross-section and event topology calculation
75
- double ecmsq = ((2.*pmap)*1.0e-3)*pc;
76
- double xln15s = log(0.15*ecmsq);
77
-
78
- //New models, see Claudia's thesis
79
- double pptot = (0.041084 - 0.0023302*log(ecmsq)) + 0.00031514 * pow(log(ecmsq),2.);
80
- double ppel = (11.7 - 1.59*log(ecmsq) + 0.134 * pow(log(ecmsq),2.))/1.0e3;
81
- double ppsd = (4.3 + 0.3*log(ecmsq))/1.0e3;
82
- double bpp = 7.156 + 1.439*log(sqrt(ecmsq));
83
-
84
- xran_cry[0] = RandomRutherford_generate(rng, part);
85
-
86
- //Rescale the total and inelastic cross-section accordigly to the average density seen
87
- double x_i = x;
88
- int np = x_i/dP; //Calculate in which crystalline plane the particle enters
89
- x_i = x_i - np*dP; //Rescale the incoming x at the left crystalline plane
90
- x_i = x_i - (dP/2.); //Rescale the incoming x in the middle of crystalline planes
91
-
92
- double pv = pow(pc,2.)/sqrt(pow(pc,2.) + pow((pmap*1.0e-3),2.))*1.0e9; //Calculate pv=P/E
93
- double Ueff = eUm*((2.*x_i)/dP)*((2.*x_i)/dP) + pv*x_i/r; //Calculate effective potential
94
- double Et = (pv*pow(xp,2.))/2. + Ueff; //Calculate transverse energy
95
- double Ec = (eUm*(1.-rc/r))*(1.-rc/r); //Calculate critical energy in bent crystals
96
-
97
- //To avoid negative Et
98
- double xminU = ((-pow(dP,2.)*pc)*1.0e9)/(8.*eUm*r);
99
- double Umin = fabs((eUm*((2.*xminU)/dP))*((2.*xminU)/dP) + pv*xminU/r);
100
- Et = Et + Umin;
101
- Ec = Ec + Umin;
102
-
103
- //Calculate min e max of the trajectory between crystalline planes
104
- double x_min = (-(dP/2.)*rc)/r - (dP/2.)*sqrt(Et/Ec);
105
- double x_max = (-(dP/2.)*rc)/r + (dP/2.)*sqrt(Et/Ec);
106
-
107
- //Change ref. frame and go back with 0 on the crystalline plane on the left
108
- x_min = x_min - dP/2.;
109
- x_max = x_max - dP/2.;
110
-
111
- //Calculate the "normal density" in m^-3
112
- double N_am = ((rho*6.022e23)*1.0e6)/anuc;
113
-
114
- //Calculate atomic density at min and max of the trajectory oscillation
115
- // erf returns the error function of complex argument
116
- double rho_max = ((N_am*dP)/2.)*(erf(x_max/sqrt(2*pow(u1,2.))) - erf((dP-x_max)/sqrt(2*pow(u1,2.))));
117
- double rho_min = ((N_am*dP)/2.)*(erf(x_min/sqrt(2*pow(u1,2.))) - erf((dP-x_min)/sqrt(2*pow(u1,2.))));
118
-
119
- //"zero-approximation" of average nuclear density seen along the trajectory
120
- double avrrho = (rho_max - rho_min)/(x_max - x_min);
121
- avrrho = (2.*avrrho)/N_am;
122
-
123
- double csref_tot_rsc = csref0*avrrho; //Rescaled total ref cs
124
- double csref_inel_rsc = csref1*avrrho; //Rescaled inelastic ref cs
125
-
126
- //Cross-section calculation
127
- double freep = freeco_cry * pow(anuc,1./3.);
128
-
129
- //compute pp and pn el+single diff contributions to cross-section (both added : quasi-elastic or qel later)
130
- cs[3] = freep*ppel;
131
- cs[4] = freep*ppsd;
132
-
133
- //correct TOT-CSec for energy dependence of qel
134
- //TOT CS is here without a Coulomb contribution
135
- cs[0] = csref_tot_rsc + freep*(pptot - pptref_cry);
136
-
137
- //Also correct inel-CS
138
- if(csref_tot_rsc == 0) {
139
- cs[1] = 0;
140
- } else {
141
- cs[1] = (csref_inel_rsc*cs[0])/csref_tot_rsc;
142
- }
143
-
144
- //Nuclear Elastic is TOT-inel-qel ( see definition in RPP)
145
- cs[2] = ((cs[0] - cs[1]) - cs[3]) - cs[4];
146
- cs[5] = csref5;
147
-
148
- //Now add Coulomb
149
- cs[0] = cs[0] + cs[5];
150
-
151
- //Calculate cumulative probability
152
- //cprob[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
153
- cprob[5] = 1;
154
-
155
- if (cs[0] == 0) {
156
- int i;
157
- for (i = 1; i < 5; ++i) {
158
- cprob[i] = cprob[i-1];
159
- }
160
- } else {
161
- int i;
162
- for (i = 1; i < 5; ++i) {
163
- cprob[i] = cprob[i-1] + cs[i]/cs[0];
164
- }
165
- }
166
-
167
- //Multiple Coulomb Scattering
168
- xp = xp*1.0e3;
169
- yp = yp*1.0e3;
170
-
171
- //Turn on/off nuclear interactions
172
- if (nam == 0) {
173
- result[0] = x;
174
- result[1] = xp;
175
- result[2] = yp;
176
- result[3] = pc;
177
- result[4] = iProc;
178
- return result;
179
- }
180
-
181
- double nuc_cl_l;
182
- //Can nuclear interaction happen?
183
- //Rescaled nuclear collision length
184
- if (avrrho == 0) {
185
- nuc_cl_l = 1.0e6;
186
- } else {
187
- nuc_cl_l = collnt/avrrho;
188
- }
189
-
190
- double zlm = nuc_cl_l*RandomExponential_generate(part);
191
-
192
- //write(889,*) x_i,pv,Ueff,Et,Ec,N_am,avrrho,csref_tot_rsc,csref_inel_rsc,nuc_cl_l
193
-
194
- if (zlm < dz) {
195
-
196
- //Choose nuclear interaction
197
- double aran = RandomUniform_generate(part);
198
- int i = 1;
199
- double bn;
200
- double xm2;
201
- double bsd = 0.0;
202
- double teta;
203
- double tx;
204
- double tz;
205
-
206
- while (aran > cprob[i]) {
207
- i=i+1;
208
- }
209
-
210
- int ichoix = i;
211
-
212
- //Do the interaction
213
- double t = 0 ; //default value to cover ichoix=1
214
-
215
- if (ichoix==1) {
216
- iProc = proc_ch_absorbed; //deep inelastic, impinging p disappeared
217
- } else if (ichoix==2) { //p-n elastic
218
- iProc = proc_ch_pne;
219
- bn = (bnref*cs[0])/csref_tot_rsc;
220
- t = RandomExponential_generate(part)/bn;
221
- } else if (ichoix==3) { //p-p elastic
222
- iProc = proc_ch_ppe;
223
- t = RandomExponential_generate(part)/bpp;
224
- } else if (ichoix==4) { //Single diffractive
225
- iProc = proc_ch_diff;
226
- xm2 = exp(RandomUniform_generate(part)*xln15s);
227
- pc = pc*(1 - xm2/ecmsq);
228
-
229
- if (xm2 < 2.) {
230
- bsd = 2*bpp;
231
- } else if (xm2 >= 2. && xm2 <= 5.) {
232
- bsd = ((106.0 - 17.0*xm2)*bpp)/36.0;
233
- } else if (xm2 > 5.) {
234
- bsd = (7*bpp)/12.0;
235
- }
236
- //end if
237
- t = RandomExponential_generate(part)/bsd;
238
- } else { //(ichoix==5)
239
- iProc = proc_ch_ruth;
240
- xran_cry[0] = RandomRutherford_generate(rng, part);
241
- t = xran_cry[0];
242
- }
243
-
244
-
245
- //Calculate the related kick -----------
246
- if (ichoix == 4) {
247
- teta = sqrt(t)/pc_in; //DIFF has changed PC!!!
248
- } else {
249
- teta = sqrt(t)/pc;
250
- }
251
-
252
- tx = teta*RandomNormal_generate(part)*1.0e3;
253
- tz = teta*RandomNormal_generate(part)*1.0e3;
254
-
255
- //Change p angle
256
- xp = xp + tx;
257
- yp = yp + tz;
258
- }
259
-
260
- xp = xp/1.0e3;
261
- yp = yp/1.0e3;
262
-
263
- result[0] = x;
264
- result[1] = xp;
265
- result[2] = yp;
266
- result[3] = pc;
267
- result[4] = iProc;
268
- return result;
269
- }
270
-
271
-
272
- /*gpufun*/
273
- double* moveam(RandomRutherfordData rng, LocalParticle* part, double nam, double dz, double dei, double dlr, double xp, double yp, double pc, double anuc, double zatom, double emr, double hcut, double bnref, double csref0, double csref1, double csref5, double collnt, double iProc) {
274
-
275
- double* result = (double*)malloc(4 * sizeof(double));
276
-
277
- // // Material properties
278
- // double const exenergy = CrystalMaterialData_get_excitation_energy(material);
279
- // double const rho = CrystalMaterialData_get_density(material);
280
- // double const anuc = CrystalMaterialData_get_A(material);
281
- // double const zatom = CrystalMaterialData_get_Z(material);
282
- // double const emr = CrystalMaterialData_get_nuclear_radius(material);
283
- // double const dlri = CrystalMaterialData_get_crystal_radiation_length(material);
284
- // double const dlyi = CrystalMaterialData_get_crystal_nuclear_length(material);
285
- // double const ai = CrystalMaterialData_get_crystal_plane_distance(material);
286
- // double const eum = CrystalMaterialData_get_crystal_potential(material);
287
- // double const collnt = CrystalMaterialData_get_nuclear_collision_length(material);
288
- // double const hcut = CrystalMaterialData_get_hcut(material);
289
- // double const bnref = CrystalMaterialData_get_nuclear_elastic_slope(material);
290
- // double const csref0 = CrystalMaterialData_get_cross_section(material, 0);
291
- // double const csref1 = CrystalMaterialData_get_cross_section(material, 1);
292
- // double const csref5 = CrystalMaterialData_get_cross_section(material, 5);
293
-
294
- double pc_in = pc;
295
-
296
- double pmap = 938.271998;
297
-
298
- double cs[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
299
- double cprob[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
300
-
301
- // New treatment of scattering routine based on standard sixtrack routine
302
- // useful calculations for cross-section and event topology calculation
303
- double ecmsq = 2.*pmap*1.0e-3*pc;
304
- double xln15s = log(0.15*ecmsq);
305
-
306
- // New models, see Claudia's thesis
307
- double pptot = 0.041084 - 0.0023302*log(ecmsq) + 0.00031514 * pow(log(ecmsq),2.);
308
- double ppel = (11.7 - 1.59*log(ecmsq) + 0.134 * pow(log(ecmsq),2.))/1.0e3;
309
- double ppsd = (4.3 + 0.3*log(ecmsq))/1.0e3;
310
- double bpp = 7.156 + 1.439*log(sqrt(ecmsq));
311
-
312
- // Cross-section calculation
313
- // freep: number of nucleons involved in single scattering
314
- double freep = freeco_cry * pow(anuc,1./3.);
315
-
316
- // Compute pp and pn el+single diff contributions to cross-section (both added : quasi-elastic or qel later)
317
- cs[3] = freep*ppel;
318
- cs[4] = freep*ppsd;
319
-
320
- // Correct TOT-CSec for energy dependence of qel
321
- // TOT CS is here without a Coulomb contribution
322
- cs[0] = csref0 + freep*(pptot - pptref_cry);
323
- double bn = (bnref*cs[0])/csref0;
324
-
325
- // Also correct inel-CS
326
- cs[1] = (csref1*cs[0])/csref0;
327
-
328
- // Nuclear Elastic is TOT-inel-qel ( see definition in RPP)
329
- cs[2] = ((cs[0] - cs[1]) - cs[3]) - cs[4];
330
- cs[5] = csref5;
331
-
332
- // Now add Coulomb
333
- cs[0] = cs[0] + cs[5];
334
-
335
- // Calculate cumulative probability
336
- cprob[5] = 1;
337
-
338
- int i;
339
- for (i = 1; i < 5; ++i) {
340
- cprob[i] = cprob[i-1] + cs[i]/cs[0];
341
- }
342
-
343
- // Multiple Coulomb Scattering
344
- xp = xp*1.0e3;
345
- yp = yp*1.0e3;
346
- pc = pc - dei*dz; // Energy lost because of ionization process[GeV]
347
-
348
- double dya = (13.6/pc)*sqrt(dz/dlr); // RMS of coloumb scattering MCS (mrad)
349
- double kxmcs = dya*RandomNormal_generate(part);
350
- double kymcs = dya*RandomNormal_generate(part);
351
-
352
- xp = xp+kxmcs;
353
- yp = yp+kymcs;
354
-
355
- if (nam == 0) {
356
-
357
- result[0] = xp;
358
- result[1] = yp;
359
- result[2] = pc;
360
- result[3] = iProc;
361
- return result; // Turn on/off nuclear interactions
362
- }
363
-
364
- // Can nuclear interaction happen?
365
- double zlm = collnt*RandomExponential_generate(part);
366
-
367
- if (zlm < dz) {
368
- // Choose nuclear interaction
369
- double aran = RandomUniform_generate(part);
370
- int i=1;
371
-
372
- while (aran > cprob[i]) {
373
- i = i+1;
374
- //goto 10
375
- }
376
-
377
- int ichoix = i;
378
-
379
- // Do the interaction
380
- double t = 0 ;// default value to cover ichoix=1
381
- if (ichoix==1) {
382
- //case(1) // Deep inelastic, impinging p disappeared
383
- iProc = proc_absorbed;
384
- } else if (ichoix==2) { // p-n elastic
385
- iProc = proc_pne;
386
- t = RandomExponential_generate(part)/bn;
387
- } else if (ichoix==3) { // p-p elastic
388
- iProc = proc_ppe;
389
- t = RandomExponential_generate(part)/bpp;
390
- } else if (ichoix==4) { // Single diffractive
391
- iProc = proc_diff;
392
- double xm2 = exp(RandomUniform_generate(part)*xln15s);
393
- double bsd = 0.0;
394
- pc = pc*(1 - xm2/ecmsq);
395
-
396
- if(xm2 < 2) {
397
- bsd = 2*bpp;
398
- } else if(xm2 >= 2 && xm2 <= 5) {
399
- bsd = ((106.0 - 17.0*xm2)*bpp)/36.0;
400
- } else if(xm2 > 5) {
401
- bsd = 7.0*bpp/12.0;
402
- }
403
-
404
- t = RandomExponential_generate(part)/bsd;
405
- } else { //(ichoix==5)
406
- iProc = proc_ruth;
407
- t = RandomRutherford_generate(rng, part);
408
- }
409
-
410
- // end select
411
-
412
- double teta;
413
-
414
- // Calculate the related kick
415
- if(ichoix == 4) {
416
- teta = sqrt(t)/pc_in ;// DIFF has changed PC
417
- } else {
418
- teta = sqrt(t)/pc;
419
- }
420
-
421
- double tx = teta*RandomNormal_generate(part)*1.0e3;
422
- double tz = teta*RandomNormal_generate(part)*1.0e3;
423
-
424
- // Change p angle
425
- xp = xp + tx;
426
- yp = yp + tz;
427
-
428
- }
429
-
430
- xp = xp/1.0e3;
431
- yp = yp/1.0e3;
432
-
433
- result[0] = xp;
434
- result[1] = yp;
435
- result[2] = pc;
436
- result[3] = iProc;
437
- return result; // Turn on/off nuclear interactions
438
- }
439
-
440
-
441
- /*gpufun*/
442
- double calcionloss_cry(LocalParticle* part, double dz, double EnLo, double betar, double bgr, double gammar, double tmax, double plen, double exenergy, double zatom, double rho, double anuc) {
443
-
444
- // // Material properties
445
- // double const exenergy = CrystalMaterialData_get_excitation_energy(material);
446
- // double const rho = CrystalMaterialData_get_density(material);
447
- // double const anuc = CrystalMaterialData_get_A(material);
448
- // double const zatom = CrystalMaterialData_get_Z(material);
449
- // double const emr = CrystalMaterialData_get_nuclear_radius(material);
450
- // double const dlri = CrystalMaterialData_get_crystal_radiation_length(material);
451
- // double const dlyi = CrystalMaterialData_get_crystal_nuclear_length(material);
452
- // double const ai = CrystalMaterialData_get_crystal_plane_distance(material);
453
- // double const eum = CrystalMaterialData_get_crystal_potential(material);
454
- // double const collnt = CrystalMaterialData_get_nuclear_collision_length(material);
455
- // double const hcut = CrystalMaterialData_get_hcut(material);
456
- // double const bnref = CrystalMaterialData_get_nuclear_elastic_slope(material);
457
- // double const csref0 = CrystalMaterialData_get_cross_section(material, 0);
458
- // double const csref1 = CrystalMaterialData_get_cross_section(material, 1);
459
- // double const csref5 = CrystalMaterialData_get_cross_section(material, 5);
460
-
461
- double k = 0.307075; // Constant in front bethe-bloch [mev g^-1 cm^2]
462
- double pmae = 0.51099890;
463
- double pmap = 938.271998;
464
-
465
- double thl = (((((4.*k)*zatom)*dz)*1.0e2)*rho)/(anuc* pow(betar,2)); // [MeV]
466
- EnLo = ((k*zatom)/(anuc* pow(betar,2.))) * (0.5*log(((((2.*pmae)*bgr)*bgr)*tmax)/(1.0e6* pow(exenergy,2.))) -
467
- pow(betar,2.) - log(plen/(exenergy*1.0e3)) - log(bgr) + 0.5);
468
- EnLo = ((EnLo*rho)*1.0e-1)*dz; // [GeV]
469
- double Tt = (EnLo*1.0e3)+thl; // [MeV]
470
-
471
- double cs_tail = ((k*zatom)/(anuc* pow(betar,2.))) * ((0.5*((1/Tt)-(1./tmax))) - (log(tmax/Tt)*(pow(betar,2.))/(2.*tmax))
472
- + ((tmax-Tt)/((4.*(pow(gammar,2.)))*(pow(pmap,2.)))));
473
- double prob_tail = ((cs_tail*rho)*dz)*1.0e2;
474
-
475
- if (RandomUniform_generate(part) < prob_tail) {
476
- EnLo = ((k*zatom)/(anuc*pow(betar,2.))) * (0.5*log((2*pmae*bgr*bgr*tmax)/(1.0e6*pow(exenergy,2.))) - pow(betar,2.) -
477
- log(plen/(exenergy*1.0e3)) - log(bgr) + 0.5 + pow(tmax,2.)/(8.*(pow(gammar,2.))*(pow(pmap,2.))));
478
-
479
- EnLo = (EnLo*rho)*1.0e-1; // [GeV/m]
480
- } else {
481
- EnLo = EnLo/dz; // [GeV/m]
482
- }
483
-
484
- return EnLo;
485
- }
486
-
487
-
488
- /*gpufun*/
489
- double* interact(RandomRutherfordData rng, LocalParticle* part, double x, double xp, double y, double yp, double pc, double length, double s_P, double x_P, double exenergy, double rho, double anuc, double zatom, double emr, double dlri, double dlyi,
490
- double ai, double eUm, double collnt, double hcut, double csref0, double csref1, double csref5, double bnref,
491
- double cry_tilt, double cry_rcurv, double cry_alayer, double cry_xmax,
492
- double cry_ymax, double cry_orient, double cry_miscut, double cry_bend, double cry_cBend, double cry_sBend, double cry_cpTilt, double cry_spTilt, double cry_cnTilt, double cry_snTilt, double iProc) {
493
-
494
- double* result = (double*)malloc(6 * sizeof(double));
495
-
496
- // // Material properties
497
- // double const exenergy = CrystalMaterialData_get_excitation_energy(material);
498
- // double const rho = CrystalMaterialData_get_density(material);
499
- // double const anuc = CrystalMaterialData_get_A(material);
500
- // double const zatom = CrystalMaterialData_get_Z(material);
501
- // double const emr = CrystalMaterialData_get_nuclear_radius(material);
502
- // double const dlri = CrystalMaterialData_get_crystal_radiation_length(material);
503
- // double const dlyi = CrystalMaterialData_get_crystal_nuclear_length(material);
504
- // double const ai = CrystalMaterialData_get_crystal_plane_distance(material);
505
- // double const eum = CrystalMaterialData_get_crystal_potential(material);
506
- // double const collnt = CrystalMaterialData_get_nuclear_collision_length(material);
507
- // double const hcut = CrystalMaterialData_get_hcut(material);
508
- // double const bnref = CrystalMaterialData_get_nuclear_elastic_slope(material);
509
- // double const csref0 = CrystalMaterialData_get_cross_section(material, 0);
510
- // double const csref1 = CrystalMaterialData_get_cross_section(material, 1);
511
- // double const csref5 = CrystalMaterialData_get_cross_section(material, 5);
512
-
513
- double dest = 0.;
514
- double pmap = 938.271998;
515
- double pmae = 0.51099890;
516
- double crade = 2.817940285e-15;
517
-
518
- double c_v1 = 1.7; // Fitting coefficient
519
- double c_v2 = -1.5; // Fitting coefficient
520
-
521
- int nam = 1; // Switch on/off the nuclear interaction (NAM) and the MCS (ZN)
522
- int zn = 1;
523
-
524
- // dE/dX and dechanneling length calculation
525
- double mom = pc*1.0e3; // [GeV]
526
- double enr = sqrt(pow(mom,2.) + pow(pmap,2.)); // [MeV]
527
- double gammar = enr/pmap;
528
- double betar = mom/enr;
529
- double bgr = betar*gammar;
530
- double mep = pmae/pmap; // Electron/proton
531
-
532
- double tmax = (2.*pmae*pow(bgr,2.))/(1. + 2.*gammar*mep + pow(mep,2.)); // [MeV]
533
- double plen = sqrt((rho*zatom)/anuc)*28.816e-6; // [MeV]
534
-
535
- double const_dech = ((256.0/(9*pow(M_PI,2.))) * (1./(log(((2.*pmae)*gammar)/(exenergy*1.0e3)) - 1.))) * ((aTF*dP)/(crade*pmae)); // [m/MeV]
536
- const_dech = const_dech*1.0e3; // [m/GeV]
537
-
538
- double s = 0.;
539
- double s_length = cry_rcurv*sin(length/cry_rcurv);
540
- double L_chan = length;
541
-
542
- // MISCUT second step: fundamental coordinates (crystal edges and plane curvature radius)
543
- double s_K = cry_rcurv*sin(length/cry_rcurv);
544
- double x_K = cry_rcurv*(1.-cos(length/cry_rcurv));
545
- double s_M = (cry_rcurv-cry_xmax)*sin(length/cry_rcurv);
546
- double x_M = cry_xmax + (cry_rcurv-cry_xmax)*(1.-cos(length/cry_rcurv));
547
- double r = sqrt(pow(s_P,2.) + pow((x-x_P),2.));
548
-
549
- // MISCUT third step: F coordinates (exit point) on crystal exit face
550
- double A_F = pow((tan(length/cry_rcurv)),2.) + 1.;
551
- double B_F = ((-2)*pow((tan(length/cry_rcurv)),2.))*cry_rcurv + (2.*tan(length/cry_rcurv))*s_P - 2.*x_P;
552
- double C_F = pow((tan(length/cry_rcurv)),2.)*(pow(cry_rcurv,2.)) - ((2.*tan(length/cry_rcurv))*s_P)*cry_rcurv + pow(s_P,2.) + pow(x_P,2.) - pow(r,2.);
553
-
554
- double x_F = (-B_F-sqrt(pow(B_F,2.)-4.*(A_F*C_F)))/(2.*A_F);
555
- double s_F = (-tan(length/cry_rcurv))*(x_F-cry_rcurv);
556
-
557
- if (x_F < x_K || x_F > x_M || s_F < s_M || s_F > s_K) {
558
-
559
- double alpha_F;
560
- double beta_F;
561
-
562
- if (cry_miscut == 0 && fabs(x_F-x_K) <= 1.0e-13 && fabs(s_F-s_K) <= 1.0e3) {
563
- // no miscut, entrance from below: exit point is K (lower edge)
564
- x_F = x_K;
565
- s_F = s_K;
566
- } else if (cry_miscut == 0 && fabs(x_F-x_M) <= 1.0e3 && fabs(s_F-s_M) <= 1.0e3) {
567
- // no miscut, entrance from above: exit point is M (upper edge)
568
- x_F = x_M;
569
- s_F = s_M;
570
- } else {
571
- // MISCUT Third step (bis): F coordinates (exit point) on bent side
572
- if (cry_miscut < 0) {
573
- // Intersect with bottom side
574
- alpha_F = (cry_rcurv-x_P)/x_P;
575
- beta_F = -(pow(r,2.)-pow(s_P,2.)-pow(x_P,2.))/(2*s_P);
576
- A_F = pow(alpha_F,2.) + 1.;
577
- B_F = 2.*(alpha_F*beta_F) - 2.*cry_rcurv;
578
- C_F = pow(beta_F,2.);
579
- } else {
580
- // Intersect with top side
581
- alpha_F = (cry_rcurv-x_P)/s_P;
582
- beta_F = -(pow(r,2.)+cry_xmax*(cry_xmax-(2.*cry_rcurv))-pow(s_P,2.)-pow(x_P,2.))/(2.*s_P);
583
- A_F = pow(alpha_F,2.) + 1.;
584
- B_F = 2.*(alpha_F*beta_F) - 2.*cry_rcurv;
585
- C_F = pow(beta_F,2.) - cry_xmax*(cry_xmax-2.*cry_rcurv);
586
- }
587
-
588
- x_F = (-B_F-sqrt(pow(B_F,2.)-4.*(A_F*C_F)))/(2.*A_F);
589
- s_F = alpha_F*x_F + beta_F;
590
- }
591
- }
592
-
593
- // MISCUT 4th step: deflection and length calculation
594
- double a = sqrt(pow(s_F,2.)+pow((x-x_F),2.));
595
- double tP = acos((2.*pow(r,2.)-pow(a,2.))/(2.*pow(r,2.)));
596
- double tdefl = asin((s_F-s_P)/r);
597
- L_chan = r*tP;
598
-
599
- double xp_rel = xp - cry_miscut;
600
-
601
- double ymin = -cry_ymax/2.;
602
- double ymax = cry_ymax/2.;
603
-
604
- // FIRST CASE: p don't interact with crystal
605
- if (y < ymin || y > ymax || x > cry_xmax) {
606
- x = x + xp*s_length;
607
- y = y + yp*s_length;
608
- iProc = proc_out;
609
- result[0] = x;
610
- result[1] = xp;
611
- result[2] = y;
612
- result[3] = yp;
613
- result[4] = pc;
614
- result[5] = iProc;
615
- return result;
616
-
617
- } else if (x < cry_alayer || y-ymin < cry_alayer || ymax-y < cry_alayer) {
618
- // SECOND CASE: p hits the amorphous layer
619
- double x0 = x;
620
- double y0 = y;
621
- double a_eq = 1. + pow(xp,2.);
622
- double b_eq = (2.*x)*xp - (2.*xp)*cry_rcurv;
623
- double c_eq = pow(x,2.) - (2.*x)*cry_rcurv;
624
- double delta = pow(b_eq,2.) - (4.*a_eq)*c_eq;
625
- s = (-b_eq+sqrt(delta))/(2.*a_eq);
626
- if (s >= s_length) {
627
- s = s_length;
628
- }
629
- x = xp*s + x0;
630
- double len_xs = sqrt(pow((x-x0),2.) + pow(s,2.));
631
- double len_ys;
632
- if (yp >= 0 && y + yp*s <= ymax) {
633
- len_ys = yp*len_xs;
634
- } else if (yp < 0 && y + yp*s >= ymin) {
635
- len_ys = yp*len_xs;
636
- } else {
637
- s = (ymax-y)/yp;
638
- len_ys = sqrt(pow((ymax-y),2.) + pow(s,2.));
639
- x = x0 + xp*s;
640
- len_xs = sqrt(pow((x-x0),2.) + pow(s,2.));
641
- }
642
-
643
- double am_len = sqrt(pow(len_xs,2.) + pow(len_ys,2.));
644
- s = s/2;
645
- x = x0 + xp*s;
646
- y = y0 + yp*s;
647
- iProc = proc_AM;
648
-
649
- dest = calcionloss_cry(part,s_length,dest,betar,bgr,gammar,tmax,plen,
650
- exenergy,zatom,rho,anuc);
651
-
652
- double* result_am = moveam(rng, part,nam,am_len,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,
653
- bnref,csref0,csref1,csref5,collnt,iProc);
654
- xp = result_am[0];
655
- yp = result_am[1];
656
- pc = result_am[2];
657
- iProc = result_am[3];
658
- free(result_am);
659
-
660
- x = x + xp*(s_length-s);
661
- y = y + yp*(s_length-s);
662
-
663
- result[0] = x;
664
- result[1] = xp;
665
- result[2] = y;
666
- result[3] = yp;
667
- result[4] = pc;
668
- result[5] = iProc;
669
- return result;
670
-
671
- } else if (x > cry_xmax-cry_alayer && x < cry_xmax) {
672
- iProc = proc_AM;
673
-
674
- dest = calcionloss_cry(part,s_length,dest,betar,bgr,gammar,tmax,plen,
675
- exenergy,zatom,rho,anuc);
676
-
677
- double* result_am = moveam(rng, part,nam,s_length,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,
678
- csref1,csref5,collnt,iProc);
679
- xp = result_am[0];
680
- yp = result_am[1];
681
- pc = result_am[2];
682
- iProc = result_am[3];
683
- free(result_am);
684
-
685
- result[0] = x;
686
- result[1] = xp;
687
- result[2] = y;
688
- result[3] = yp;
689
- result[4] = pc;
690
- result[5] = iProc;
691
- return result;
692
- }
693
-
694
- //THIRD CASE: the p interacts with the crystal.
695
- //Define typical angles/probabilities for orientation 110
696
- double xpcrit0 = sqrt((2.0e-9*eUm)/pc); //Critical angle (rad) for straight crystals
697
- double Rcrit = (pc/(2.0e-6*eUm))*ai; //Critical curvature radius [m]
698
-
699
- //If R>Rcritical=>no channeling is possible (ratio<1)
700
- double ratio = cry_rcurv/Rcrit;
701
- double xpcrit = (xpcrit0*(cry_rcurv-Rcrit))/cry_rcurv; //Critical angle for curved crystal
702
-
703
- double Ang_rms;
704
- double Ang_avr;
705
- double Vcapt;
706
- if (ratio <= 1.) { //no possibile channeling
707
- Ang_rms = ((c_v1*0.42)*xpcrit0)*sin(1.4*ratio); //RMS scattering
708
- Ang_avr = ((c_v2*xpcrit0)*5.0e-2)*ratio; //Average angle reflection
709
- Vcapt = 0.; //Probability of VC
710
- } else if (ratio <= 3.) { //Strongly bent crystal
711
- Ang_rms = ((c_v1*0.42)*xpcrit0)*sin(0.4713*ratio + 0.85); //RMS scattering
712
- Ang_avr = (c_v2*xpcrit0)*(0.1972*ratio - 0.1472); //Average angle reflection
713
- Vcapt = 7.0e-4*(ratio - 0.7)/pow(pc,2.0e-1); //Correction by sasha drozdin/armen
714
- //K=0.0007 is taken based on simulations using CATCH.f (V.Biryukov)
715
- } else { //Rcry >> Rcrit
716
- Ang_rms = (c_v1*xpcrit0)*(1./ratio); //RMS scattering
717
- Ang_avr = (c_v2*xpcrit0)*(1. - 1.6667/ratio); //Average angle for VR
718
- Vcapt = 7.0e-4*(ratio - 0.7)/pow(pc,2.0e-1); //Probability for VC correction by sasha drozdin/armen
719
- //K=0.0007 is taken based on simulations using CATCH.f (V.Biryukov)
720
- }
721
- if (cry_orient == 2) {
722
- Ang_avr = Ang_avr*0.93;
723
- Ang_rms = Ang_rms*1.05;
724
- xpcrit = xpcrit*0.98;
725
- }
726
- if (fabs(xp_rel) < xpcrit) {
727
- double alpha = xp_rel/xpcrit;
728
- double Chann = sqrt(0.9*(1 - pow(alpha,2.)))*sqrt(1.-(1./ratio)); //Saturation at 95%
729
- double N_atom = 1.0e-1;
730
-
731
- //if they can channel: 2 options
732
- if (RandomUniform_generate(part) <= Chann) { //option 1:channeling
733
- double TLdech1 = (const_dech*pc)*pow((1.-1./ratio),2.); //Updated calculate typical dech. length(m)
734
-
735
- if(RandomUniform_generate(part) <= N_atom) {
736
- TLdech1 = ((const_dech/2.0e2)*pc)*pow((1.-1./ratio),2.); //Updated dechanneling length (m)
737
- }
738
- double Dechan = RandomExponential_generate(part); //Probability of dechanneling
739
- double Ldech = TLdech1*Dechan; //Actual dechan. length
740
-
741
- //careful: the dechanneling lentgh is along the trajectory
742
- //of the particle -not along the longitudinal coordinate...
743
- if (Ldech < L_chan) {
744
- iProc = proc_DC;
745
- double Dxp = Ldech/r; //Change angle from channeling [mrad]
746
- double Sdech = Ldech*cos(cry_miscut + 0.5*Dxp);
747
- x = x + Ldech*(sin(0.5*Dxp+cry_miscut)); //Trajectory at channeling exit
748
- xp = xp + Dxp + (2*(RandomUniform_generate(part)-0.5))*xpcrit;
749
- y = y + yp * Sdech;
750
-
751
- dest = calcionloss_cry(part,Ldech,dest,betar,bgr,gammar,tmax,plen,
752
- exenergy,zatom,rho,anuc);
753
- pc = pc - 0.5*dest*Ldech; //Energy loss to ionization while in CH [GeV]
754
- x = x + (0.5*(s_length-Sdech))*xp;
755
- y = y + (0.5*(s_length-Sdech))*yp;
756
-
757
- dest = calcionloss_cry(part,s_length-Sdech,dest,betar,bgr,gammar,tmax,plen,exenergy,zatom,rho,anuc);
758
-
759
- double* result_am = moveam(rng,part,nam,s_length-Sdech,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,csref1,csref5,collnt,iProc);
760
- xp = result_am[0];
761
- yp = result_am[1];
762
- pc = result_am[2];
763
- iProc = result_am[3];
764
- free(result_am);
765
-
766
- x = x + (0.5*(s_length-Sdech))*xp;
767
- y = y + (0.5*(s_length-Sdech))*yp;
768
- } else {
769
- iProc = proc_CH;
770
- double xpin = xp;
771
- double ypin = yp;
772
-
773
- //check if a nuclear interaction happen while in CH
774
- double* result_ch = movech(rng,part,nam,L_chan,x,xp,yp,pc,cry_rcurv,Rcrit,rho,anuc,zatom,emr,hcut,bnref,
775
- csref0,csref1,csref5,eUm,collnt,iProc);
776
- x = result_ch[0];
777
- xp = result_ch[1];
778
- yp = result_ch[2];
779
- pc = result_ch[3];
780
- iProc = result_ch[4];
781
- free(result_ch);
782
-
783
- if (iProc != proc_CH) {
784
- //if an nuclear interaction happened, move until the middle with initial xp,yp:
785
- //propagate until the "crystal exit" with the new xp,yp accordingly with the rest
786
- //of the code in "thin lens approx"
787
- x = x + (0.5*L_chan)*xpin;
788
- y = y + (0.5*L_chan)*ypin;
789
- x = x + (0.5*L_chan)*xp;
790
- y = y + (0.5*L_chan)*yp;
791
-
792
- dest = calcionloss_cry(part,length,dest,betar,bgr,gammar,tmax,plen,
793
- exenergy,zatom,rho,anuc);
794
- pc = pc - dest*length; //energy loss to ionization [GeV]
795
- } else {
796
- double Dxp = tdefl + (0.5*RandomNormal_generate(part))*xpcrit; //Change angle[rad]
797
-
798
- xp = Dxp;
799
- x = x + L_chan*(sin(0.5*Dxp)); //Trajectory at channeling exit
800
- y = y + s_length * yp;
801
-
802
- dest = calcionloss_cry(part,length,dest,betar,bgr,gammar,tmax,plen,exenergy,zatom,rho,anuc);
803
- pc = pc - (0.5*dest)*length; //energy loss to ionization [GeV]
804
- }
805
- }
806
- } else { //Option 2: VR
807
- //good for channeling but don't channel (1-2)
808
- iProc = proc_VR;
809
-
810
- xp = xp + (0.45*(xp_rel/xpcrit + 1))*Ang_avr;
811
- x = x + (0.5*s_length)*xp;
812
- y = y + (0.5*s_length)*yp;
813
-
814
- dest = calcionloss_cry(part,s_length,dest,betar,bgr,gammar,tmax,plen,exenergy,zatom,rho,anuc);
815
- double* result_am = moveam(rng, part,nam,s_length,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,csref1,csref5,collnt,iProc);
816
- xp = result_am[0];
817
- yp = result_am[1];
818
- pc = result_am[2];
819
- iProc = result_am[3];
820
- free(result_am);
821
-
822
- x = x + (0.5*s_length)*xp;
823
- y = y + (0.5*s_length)*yp;
824
- }
825
- } else { //case 3-2: no good for channeling. check if the can VR
826
- double Lrefl = xp_rel*r; //Distance of refl. point [m]
827
- double Srefl = sin(xp_rel/2. + cry_miscut)*Lrefl;
828
-
829
- if (Lrefl > 0 && Lrefl < L_chan) { //VR point inside
830
-
831
- //2 options: volume capture and volume reflection
832
-
833
- if (RandomUniform_generate(part) > Vcapt || zn == 0) { //Option 1: VR
834
- iProc = proc_VR;
835
- x = x + xp*Srefl;
836
- y = y + yp*Srefl;
837
- double Dxp = Ang_avr;
838
- xp = xp + Dxp + Ang_rms*RandomNormal_generate(part);
839
- x = x + (0.5*xp)*(s_length - Srefl);
840
- y = y + (0.5*yp)*(s_length - Srefl);
841
-
842
- dest = calcionloss_cry(part,s_length-Srefl,dest,betar,bgr,gammar,tmax,plen,exenergy,zatom,rho,anuc);
843
- double* result_am = moveam(rng,part,nam,s_length-Srefl,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,csref1,csref5,collnt,iProc);
844
- xp = result_am[0];
845
- yp = result_am[1];
846
- pc = result_am[2];
847
- iProc = result_am[3];
848
- free(result_am);
849
-
850
- x = x + (0.5*xp)*(s_length - Srefl);
851
- y = y + (0.5*yp)*(s_length - Srefl);
852
- } else { //Option 2: VC
853
- x = x + xp*Srefl;
854
- y = y + yp*Srefl;
855
-
856
- double TLdech2 = (const_dech/1.0e1)*pc*pow((1-1/ratio),2.) ; //Updated typical dechanneling length(m)
857
- double Ldech = TLdech2 * pow((sqrt(1.0e-2 + RandomExponential_generate(part)) - 1.0e-1),2.); //Updated DC length
858
- double tdech = Ldech/cry_rcurv;
859
- double Sdech = Ldech*cos(xp + 0.5*tdech);
860
-
861
- if (Ldech < length-Lrefl) {
862
- iProc = proc_DC;
863
- double Dxp = Ldech/cry_rcurv + (0.5*RandomNormal_generate(part))*xpcrit;
864
- x = x + Ldech*(sin(0.5*Dxp+xp)); //Trajectory at channeling exit
865
- y = y + Sdech*yp;
866
- xp = Dxp;
867
- double Red_S = (s_length - Srefl) - Sdech;
868
- x = x + (0.5*xp)*Red_S;
869
- y = y + (0.5*yp)*Red_S;
870
-
871
- dest = calcionloss_cry(part,Srefl,dest,betar,bgr,gammar,tmax,plen,
872
- exenergy,zatom,rho,anuc);
873
-
874
- pc = pc - dest*Srefl; //"added" energy loss before capture
875
-
876
- dest = calcionloss_cry(part,Sdech,dest,betar,bgr,gammar,tmax,plen,
877
- exenergy,zatom,rho,anuc);
878
- pc = pc - (0.5*dest)*Sdech; //"added" energy loss while captured
879
-
880
- dest = calcionloss_cry(part,Red_S,dest,betar,bgr,gammar,tmax,plen,
881
- exenergy,zatom,rho,anuc);
882
- double* result_am = moveam(rng,part,nam,Red_S,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,
883
- csref1,csref5,collnt,iProc);
884
- xp = result_am[0];
885
- yp = result_am[1];
886
- pc = result_am[2];
887
- iProc = result_am[3];
888
- free(result_am);
889
-
890
- x = x + (0.5*xp)*Red_S;
891
- y = y + (0.5*yp)*Red_S;
892
- } else {
893
- iProc = proc_VC;
894
- double Rlength = length - Lrefl;
895
- double tchan = Rlength/cry_rcurv;
896
- double Red_S = Rlength*cos(xp + 0.5*tchan);
897
-
898
- dest = calcionloss_cry(part,Lrefl,dest,betar,bgr,gammar,tmax,plen,
899
- exenergy,zatom,rho,anuc);
900
- pc = pc - dest*Lrefl; //"added" energy loss before capture
901
- double xpin = xp;
902
- double ypin = yp;
903
-
904
- //Check if a nuclear interaction happen while in ch
905
- double* result_ch = movech(rng,part,nam,Rlength,x,xp,yp,pc,cry_rcurv,Rcrit,rho,anuc,zatom,emr,hcut,bnref,
906
- csref0,csref1,csref5,eUm,collnt,iProc);
907
- x = result_ch[0];
908
- xp = result_ch[1];
909
- yp = result_ch[2];
910
- pc = result_ch[3];
911
- iProc = result_ch[4];
912
- free(result_ch);
913
-
914
- if (iProc != proc_VC) {
915
- //if an nuclear interaction happened, move until the middle with initial xp,yp: propagate until
916
- //the "crystal exit" with the new xp,yp aciordingly with the rest of the code in "thin lens approx"
917
- x = x + (0.5*Rlength)*xpin;
918
- y = y + (0.5*Rlength)*ypin;
919
- x = x + (0.5*Rlength)*xp;
920
- y = y + (0.5*Rlength)*yp;
921
-
922
- dest = calcionloss_cry(part,Rlength,dest,betar,bgr,gammar,tmax,plen,
923
- exenergy,zatom,rho,anuc);
924
- pc = pc - dest*Rlength;
925
- } else {
926
- double Dxp = (length-Lrefl)/cry_rcurv;
927
- x = x + sin(0.5*Dxp+xp)*Rlength; //Trajectory at channeling exit
928
- y = y + Red_S*yp;
929
- xp = tdefl + (0.5*RandomNormal_generate(part))*xpcrit; //[mrad]
930
-
931
- dest = calcionloss_cry(part,Rlength,dest,betar,bgr,gammar,tmax,plen,
932
- exenergy,zatom,rho,anuc);
933
- pc = pc - (0.5*dest)*Rlength; //"added" energy loss once captured
934
- }
935
- }
936
- }
937
- } else {
938
- //Case 3-3: move in amorphous substance (big input angles)
939
- //Modified for transition vram daniele
940
- if (xp_rel > tdefl-cry_miscut + 2*xpcrit || xp_rel < -xpcrit) {
941
- iProc = proc_AM;
942
- x = x + (0.5*s_length)*xp;
943
- y = y + (0.5*s_length)*yp;
944
- if(zn > 0) {
945
- dest = calcionloss_cry(part,s_length,dest,betar,bgr,gammar,tmax,plen,
946
- exenergy,zatom,rho,anuc);
947
- double* result_am = moveam(rng,part,nam,s_length,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,
948
- csref1,csref5,collnt,iProc);
949
- xp = result_am[0];
950
- yp = result_am[1];
951
- pc = result_am[2];
952
- iProc = result_am[3];
953
- free(result_am);
954
- }
955
-
956
- x = x + (0.5*s_length)*xp;
957
- y = y + (0.5*s_length)*yp;
958
- } else {
959
- double Pvr = (xp_rel-(tdefl-cry_miscut))/(2.*xpcrit);
960
- if(RandomUniform_generate(part) > Pvr) {
961
-
962
- iProc = proc_TRVR;
963
- x = x + xp*Srefl;
964
- y = y + yp*Srefl;
965
-
966
- double Dxp = (((-3.*Ang_rms)*xp_rel)/(2.*xpcrit) + Ang_avr) + ((3.*Ang_rms)*(tdefl-cry_miscut))/(2.*xpcrit);
967
- xp = xp + Dxp;
968
- x = x + (0.5*xp)*(s_length-Srefl);
969
- y = y + (0.5*yp)*(s_length-Srefl);
970
-
971
- dest = calcionloss_cry(part,s_length-Srefl,dest,betar,bgr,gammar,tmax,plen,
972
- exenergy,zatom,rho,anuc);
973
- double* result_am = moveam(rng,part,nam,s_length-Srefl,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,
974
- csref1,csref5,collnt,iProc);
975
- xp = result_am[0];
976
- yp = result_am[1];
977
- pc = result_am[2];
978
- iProc = result_am[3];
979
- free(result_am);
980
-
981
- x = x + (0.5*xp)*(s_length - Srefl);
982
- y = y + (0.5*yp)*(s_length - Srefl);
983
- } else {
984
- iProc = proc_TRAM;
985
- x = x + xp*Srefl;
986
- y = y + yp*Srefl;
987
- double Dxp = ((((-1.*(13.6/pc))*sqrt(s_length/dlri))*1.0e-3)*xp_rel)/(2.*xpcrit) + (((13.6/pc)*sqrt(s_length/dlri))*1.0e-3)*(1.+(tdefl-cry_miscut)/(2.*xpcrit));
988
- xp = xp+Dxp;
989
- x = x + (0.5*xp)*(s_length-Srefl);
990
- y = y + (0.5*yp)*(s_length-Srefl);
991
-
992
- dest = calcionloss_cry(part,s_length-Srefl,dest,betar,bgr,gammar,tmax,plen,
993
- exenergy,zatom,rho,anuc);
994
- double* result_am = moveam(rng,part,nam,s_length-Srefl,dest,dlri,xp,yp,pc,anuc,zatom,emr,hcut,bnref,csref0,
995
- csref1,csref5,collnt,iProc);
996
- xp = result_am[0];
997
- yp = result_am[1];
998
- pc = result_am[2];
999
- iProc = result_am[3];
1000
- free(result_am);
1001
-
1002
- x = x + (0.5*xp)*(s_length - Srefl);
1003
- y = y + (0.5*yp)*(s_length - Srefl);
1004
- }
1005
- }
1006
- }
1007
- }
1008
-
1009
- result[0] = x;
1010
- result[1] = xp;
1011
- result[2] = y;
1012
- result[3] = yp;
1013
- result[4] = pc;
1014
- result[5] = iProc;
1015
- return result;
1016
- }
1017
-
1018
-
1019
- /*gpufun*/
1020
- double* crystal(RandomRutherfordData rng, LocalParticle* part, double x, double xp, double z, double zp, double s, double p,
1021
- double x0, double xp0, double zlm, double s_imp, int isimp, double val_part_hit, double val_part_abs,
1022
- double val_part_impact, double val_part_indiv, double c_length, CrystalMaterialData material, double nhit,
1023
- double nabs, double cry_tilt, double cry_rcurv, double cry_bend, double cry_alayer, double cry_xmax,
1024
- double cry_ymax, double cry_orient, double cry_miscut, double iProc,
1025
- double n_chan, double n_VR, double n_amorphous) {
1026
-
1027
- double const exenergy = CrystalMaterialData_get_excitation_energy(material);
1028
- double const rho = CrystalMaterialData_get_density(material);
1029
- double const anuc = CrystalMaterialData_get_A(material);
1030
- double const zatom = CrystalMaterialData_get_Z(material);
1031
- double const emr = CrystalMaterialData_get_nuclear_radius(material);
1032
- double const dlri = CrystalMaterialData_get_crystal_radiation_length(material);
1033
- double const dlyi = CrystalMaterialData_get_crystal_nuclear_length(material);
1034
- double const ai = CrystalMaterialData_get_crystal_plane_distance(material);
1035
- double const eum = CrystalMaterialData_get_crystal_potential(material);
1036
- double const collnt = CrystalMaterialData_get_nuclear_collision_length(material);
1037
- double const hcut = CrystalMaterialData_get_hcut(material);
1038
- double const bnref = CrystalMaterialData_get_nuclear_elastic_slope(material);
1039
- double const csref0 = CrystalMaterialData_get_cross_section(material, 0);
1040
- double const csref1 = CrystalMaterialData_get_cross_section(material, 1);
1041
- double const csref5 = CrystalMaterialData_get_cross_section(material, 5);
1042
-
1043
- double s_temp = 0.;
1044
- double s_shift = 0.;
1045
- double s_rot = 0.;
1046
- double s_int = 0.;
1047
- double x_temp = 0.;
1048
- double x_shift = 0.;
1049
- double x_rot = 0.;
1050
- double x_int = 0.;
1051
- double xp_temp = 0.;
1052
- double xp_shift = 0.;
1053
- double xp_rot = 0.;
1054
- double xp_int = 0.;
1055
- double xp_tangent = 0.;
1056
- double tilt_int = 0.;
1057
- double shift = 0.;
1058
- double delta = 0.;
1059
- double a_eq = 0.;
1060
- double b_eq = 0.;
1061
- double c_eq = 0.;
1062
- double cry_length = c_length;
1063
-
1064
- s_imp = 0.;
1065
- iProc = proc_out;
1066
-
1067
- double* crystal_result = (double*)malloc(21 * sizeof(double));
1068
-
1069
- double const cry_cBend = cos(cry_bend);
1070
- double const cry_sBend = sin(cry_bend);
1071
-
1072
- // Transform in the crystal reference system
1073
- // 1st transformation: shift of the center of the reference frame
1074
- double const cry_cpTilt = cos(cry_tilt);
1075
- double const cry_spTilt = sin(cry_tilt);
1076
- double const cry_cnTilt = cry_cpTilt;
1077
- double const cry_snTilt = -cry_spTilt;
1078
- if (cry_tilt < 0) {
1079
- s_shift = s;
1080
- shift = cry_rcurv*(1 - cry_cpTilt);
1081
-
1082
- if (cry_tilt < -cry_bend) {
1083
- shift = cry_rcurv*(cry_cnTilt - cos(cry_bend - cry_tilt));
1084
- }
1085
- x_shift = x - shift;
1086
- } else {
1087
- s_shift = s;
1088
- x_shift = x;
1089
- }
1090
-
1091
- // 2nd transformation: rotation
1092
- s_rot = x_shift*cry_spTilt + s_shift*cry_cpTilt;
1093
- x_rot = x_shift*cry_cpTilt - s_shift*cry_spTilt;
1094
- xp_rot = xp - cry_tilt;
1095
-
1096
- // 3rd transformation: drift to the new coordinate s=0
1097
- xp = xp_rot;
1098
- x = x_rot - xp_rot*s_rot;
1099
- z = z - zp*s_rot;
1100
- s = 0.;
1101
-
1102
- // Check that particle hit the crystal
1103
- if (x >= 0. && x < cry_xmax) {
1104
- // MISCUT first step: P coordinates (center of curvature of crystalline planes)
1105
- double s_P = (cry_rcurv-cry_xmax)*sin(-cry_miscut);
1106
- double x_P = cry_xmax + (cry_rcurv-cry_xmax)*cos(-cry_miscut);
1107
-
1108
- double* result = interact(rng,part,x,xp,z,zp,p,cry_length,s_P,x_P,exenergy,rho,anuc,zatom,emr,dlri,dlyi,
1109
- ai,eum,collnt,hcut,csref0,csref1,csref5,bnref,cry_tilt,
1110
- cry_rcurv,cry_alayer,cry_xmax,cry_ymax,cry_orient,cry_miscut,cry_bend,cry_cBend,
1111
- cry_sBend,cry_cpTilt,cry_spTilt,cry_cnTilt,cry_snTilt,iProc);
1112
-
1113
- x = result[0];
1114
- xp = result[1];
1115
- z = result[2];
1116
- zp = result[3];
1117
- p = result[4];
1118
- iProc = result[5];
1119
- free(result);
1120
-
1121
- s = cry_rcurv*cry_sBend;
1122
- zlm = cry_rcurv*cry_sBend;
1123
-
1124
- if (iProc != proc_out) {
1125
- isimp = 1;
1126
- nhit = nhit + 1.;
1127
- val_part_hit = 1.;
1128
- val_part_impact = x0;
1129
- val_part_indiv = xp0;
1130
- }
1131
-
1132
- } else {
1133
-
1134
- if (x < 0) { // Crystal can be hit from below
1135
- xp_tangent = sqrt((-(2.*x)*cry_rcurv + pow(x,2.))/(pow(cry_rcurv,2.)));
1136
- } else { // Crystal can be hit from above
1137
- xp_tangent = asin((cry_rcurv*(1. - cry_cBend) - x)/sqrt(((2.*cry_rcurv)*(cry_rcurv - x))*(1 - cry_cBend) + pow(x,2.)));
1138
- }
1139
- // If the hit is below, the angle must be greater or equal than the tangent,
1140
- // or if the hit is above, the angle must be smaller or equal than the tangent
1141
- if ((x < 0. && xp >= xp_tangent) || (x >= 0. && xp <= xp_tangent)) {
1142
-
1143
- // If it hits the crystal, calculate in which point and apply the transformation and drift to that point
1144
- a_eq = 1 + pow(xp,2.);
1145
- b_eq = (2.*xp)*(x - cry_rcurv);
1146
- c_eq = -(2.*x)*cry_rcurv + pow(x,2.);
1147
- delta = pow(b_eq,2.) - 4*(a_eq*c_eq);
1148
- s_int = (-b_eq - sqrt(delta))/(2*a_eq);
1149
- s_imp = s_int;
1150
-
1151
- // MISCUT first step: P coordinates (center of curvature of crystalline planes)
1152
- double s_P_tmp = (cry_rcurv-cry_xmax)*sin(-cry_miscut);
1153
- double x_P_tmp = cry_xmax + (cry_rcurv-cry_xmax)*cos(-cry_miscut);
1154
-
1155
- if (s_int < cry_rcurv*cry_sBend) {
1156
- // Transform to a new reference system: shift and rotate
1157
- x_int = xp*s_int + x;
1158
- xp_int = xp;
1159
- z = z + zp*s_int;
1160
- x = 0.;
1161
- s = 0.;
1162
-
1163
- tilt_int = s_int/cry_rcurv;
1164
- xp = xp-tilt_int;
1165
-
1166
- // MISCUT first step (bis): transform P in new reference system
1167
- // Translation
1168
- s_P_tmp = s_P_tmp - s_int;
1169
- x_P_tmp = x_P_tmp - x_int;
1170
- // Rotation
1171
- double s_P = s_P_tmp*cos(tilt_int) + x_P_tmp*sin(tilt_int);
1172
- double x_P = -s_P_tmp*sin(tilt_int) + x_P_tmp*cos(tilt_int);
1173
-
1174
- double* result = interact(rng,part,x,xp,z,zp,p,cry_length-(tilt_int*cry_rcurv),s_P,x_P,exenergy,rho,anuc,
1175
- zatom,emr,dlri,dlyi,ai,eum,collnt,hcut,csref0,csref1,csref5,bnref,
1176
- cry_tilt,cry_rcurv,cry_alayer,cry_xmax,cry_ymax,cry_orient,cry_miscut,
1177
- cry_bend,cry_cBend,cry_sBend,cry_cpTilt,cry_spTilt,cry_cnTilt,cry_snTilt,iProc);
1178
-
1179
- x = result[0];
1180
- xp = result[1];
1181
- z = result[2];
1182
- zp = result[3];
1183
- p = result[4];
1184
- iProc = result[5];
1185
- free(result);
1186
-
1187
- s = cry_rcurv*sin(cry_bend - tilt_int);
1188
- zlm = cry_rcurv*sin(cry_bend - tilt_int);
1189
-
1190
- if (iProc != proc_out) {
1191
- x_rot = x_int;
1192
- s_rot = s_int;
1193
- xp_rot = xp_int;
1194
- s_shift = s_rot*cry_cnTilt + x_rot*cry_snTilt;
1195
- x_shift = -s_rot*cry_snTilt + x_rot*cry_cnTilt;
1196
- xp_shift = xp_rot + cry_tilt;
1197
-
1198
- if (cry_tilt < 0.) {
1199
- x0 = x_shift + shift;
1200
- xp0 = xp_shift;
1201
- }
1202
- else {
1203
- x0 = x_shift;
1204
- xp0 = xp_shift;
1205
- }
1206
- isimp = 1;
1207
- nhit = nhit + 1.;
1208
- val_part_hit = 1.;
1209
- val_part_impact = x0;
1210
- val_part_indiv = xp0;
1211
- //
1212
- }
1213
-
1214
- // un-rotate
1215
- x_temp = x;
1216
- s_temp = s;
1217
- xp_temp = xp;
1218
- s = s_temp*cos(-tilt_int) + x_temp*sin(-tilt_int);
1219
- x = -s_temp*sin(-tilt_int) + x_temp*cos(-tilt_int);
1220
- xp = xp_temp + tilt_int;
1221
-
1222
- // 2nd: shift back the 2 axis
1223
- x = x + x_int;
1224
- s = s + s_int;
1225
- } else {
1226
- s = cry_rcurv*sin(cry_length/cry_rcurv);
1227
- x = x + s*xp;
1228
- z = z + s*zp;
1229
- }
1230
- } else {
1231
- s = cry_rcurv*sin(cry_length/cry_rcurv);
1232
- x = x + s*xp;
1233
- z = z + s*zp;
1234
- }
1235
- }
1236
-
1237
- // transform back from the crystal to the collimator reference system
1238
- // 1st: un-rotate the coordinates
1239
- x_rot = x;
1240
- s_rot = s;
1241
- xp_rot = xp;
1242
-
1243
- s_shift = s_rot*cry_cnTilt + x_rot*cry_snTilt;
1244
- x_shift = -s_rot*cry_snTilt + x_rot*cry_cnTilt;
1245
- xp_shift = xp_rot + cry_tilt;
1246
-
1247
- // 2nd: shift back the reference frame
1248
- if (cry_tilt < 0) {
1249
- s = s_shift;
1250
- x = x_shift + shift;
1251
- xp = xp_shift;
1252
- } else {
1253
- x = x_shift;
1254
- s = s_shift;
1255
- xp = xp_shift;
1256
- }
1257
- //
1258
-
1259
- // 3rd: shift to new S=Length position
1260
- x = xp*(c_length - s) + x;
1261
- z = zp*(c_length - s) + z;
1262
- s = c_length;
1263
-
1264
- nabs = 0;
1265
-
1266
- if (iProc == proc_AM) {
1267
- n_amorphous = n_amorphous + 1;
1268
- } else if (iProc == proc_VR) {
1269
- n_VR = n_VR + 1;
1270
- } else if (iProc == proc_CH) {
1271
- n_chan = n_chan + 1;
1272
- } else if (iProc == proc_absorbed) {
1273
- nabs = 1; // TODO: do we need to set part_abs_pos etc?
1274
- } else if (iProc == proc_ch_absorbed) {
1275
- nabs = 1;
1276
- }
1277
-
1278
- crystal_result[0] = val_part_hit;
1279
- crystal_result[1] = val_part_abs;
1280
- crystal_result[2] = val_part_impact;
1281
- crystal_result[3] = val_part_indiv;
1282
- crystal_result[4] = nhit;
1283
- crystal_result[5] = nabs;
1284
- crystal_result[6] = s_imp;
1285
- crystal_result[7] = isimp;
1286
- crystal_result[8] = s;
1287
- crystal_result[9] = zlm;
1288
- crystal_result[10] = x;
1289
- crystal_result[11] = xp;
1290
- crystal_result[12] = x0;
1291
- crystal_result[13] = xp0;
1292
- crystal_result[14] = z;
1293
- crystal_result[15] = zp;
1294
- crystal_result[16] = p;
1295
- crystal_result[17] = iProc;
1296
- crystal_result[18] = n_chan;
1297
- crystal_result[19] = n_VR;
1298
- crystal_result[20] = n_amorphous;
1299
- return crystal_result;
1300
- }
1301
-
1302
- #endif /* XCOLL_EVEREST_CRYSTAL_INTERACT_H */