1 from __future__ import division
2 from __future__ import absolute_import
3 from __future__ import print_function
4 import math
5 import random
6 from six.moves import range
7
9
11 if max is None:
12 self.min = 1
13 self.max = min + 1
14 else:
15 self.min = min
16 self.max = max + 1
17 list.__init__(self,[0]*(self.max-self.min))
18
19
21 assert self.min <= index < self.max, 'outside range %s <= %s < %s' % (self.min, index, self.max)
22 return list.__getitem__(self, index - self.min)
23
25 assert self.min <= index < self.max
26 return list.__setitem__(self, index - self.min , value)
27
29
30 - def __init__(self, min, max=(None,None)):
41
47
54
55
57 """ A Error class for RAMBO routine """
58 pass
59
61 """***********************************************************************
62 * RAMBO *
63 * RA(NDOM) M(OMENTA) B(EAUTIFULLY) O(RGANIZED) *
64 * *
65 * A DEMOCRATIC MULTI-PARTICLE PHASE SPACE GENERATOR *
66 * AUTHORS: S.D. ELLIS, R. KLEISS, W.J. STIRLING *
67 * -- ADJUSTED BY HANS KUIJF, WEIGHTS ARE LOGARITHMIC (20-08-90) *
68 * THIS IS PY VERSION 1.0 - WRITTEN BY O. MATTELAER *
69 * *
70 * N = NUMBER OF PARTICLES *
71 * ET = TOTAL CENTRE-OF-MASS ENERGY *
72 * XM = PARTICLE MASSES ( DIM=NEXTERNAL-nincoming ) *
73 * RETURN *
74 * P = PARTICLE MOMENTA ( DIM=(4,NEXTERNAL-nincoming) ) *
75 * WT = WEIGHT OF THE EVENT *
76 ***********************************************************************"""
77
78 acc = 1e-14
79 itmax = 6
80 ibegin = 0
81 iwarn = FortranList(5)
82 Nincoming = 2
83
84
85
86 Z = FortranList(N)
87 Q = DoubleFortranList((4,N))
88 P = DoubleFortranList((4,N))
89 R = FortranList(4)
90 B = FortranList(3)
91 XM2 = FortranList(N)
92 P2 = FortranList(N)
93 E = FortranList(N)
94 V= FortranList(N)
95 IWARN = [0,0]
96
97 assert isinstance(XM, FortranList)
98 assert XM.min == 1
99 assert XM.max == N+1
100
101
102 if not ibegin:
103 ibegin = 1
104 twopi = 8 * math.atan(1)
105 po2log = math.log(twopi/4)
106 Z[2] = po2log
107 for k in range(3, N+1):
108 Z[k] = Z[k-1] + po2log - 2.*math.log(k-2) - math.log(k-1)
109
110
111 assert 1 < N < 101
112
113
114 xmt = 0
115 nm = 0
116 for i in range(1,N+1):
117 if XM[i] != 0:
118 nm +=1
119 xmt += abs(XM[i])
120
121 if xmt > ET:
122 raise RAMBOError(' Not enough energy in this case')
123
124
125
126
127
128 for i in range(1,N+1):
129 r1=random_nb(1)
130 c = 2 * r1 -1
131 s = math.sqrt(1 - c**2)
132 f = twopi * random_nb(2)
133 r1 = random_nb(3)
134 r2 = random_nb(4)
135
136 Q[(4,i)]=-math.log(r1*r2)
137 Q[(3,i)]= Q[(4,i)]*c
138 Q[(2,i)]=Q[(4,i)]*s*math.cos(f)
139 Q[(1,i)]=Q[(4,i)]*s*math.sin(f)
140
141
142 for i in range(1, N+1):
143 for k in range(1,5):
144 R[k] = R[k] + Q[(k,i)]
145 rmas = math.sqrt(R[4]**2-R[3]**2-R[2]**2-R[1]**2)
146 for k in range(1,4):
147 B[k] = - R[k]/rmas
148
149 g = R[4] / rmas
150 a = 1.0 / (1+g)
151 x = ET / rmas
152
153
154 for i in range(1, N+1):
155 bq = B[1]*Q[(1,i)]+B[2]*Q[(2,i)]+B[3]*Q[(3,i)]
156 for k in range(1,4):
157 P[k,i] = x*(Q[(k,i)]+B[k]*(Q[(4,i)]+a*bq))
158 P[(4,i)] = x*(g*Q[(4,i)]+bq)
159
160
161 wt = po2log
162 if N != 2:
163 wt = (2 * N-4) * math.log(ET) + Z[N]
164 if wt < -180 and iwarn[1] < 5:
165 print("RAMBO WARNS: WEIGHT = EXP(%f20.9) MAY UNDERFLOW" % wt)
166 iwarn[1] += 1
167 if wt > 174 and iwarn[2] < 5:
168 print(" RAMBO WARNS: WEIGHT = EXP(%f20.9) MAY OVERFLOW" % wt)
169 iwarn[2] += 1
170
171
172
173 if nm == 0:
174 return P, wt
175
176
177
178 xmax = math.sqrt(1-(xmt/ET)**2)
179 for i in range(1,N+1):
180 XM2[i] = XM[i] **2
181 P2[i] = P[(4,i)]**2
182 n_iter = 0
183 x= xmax
184 accu = ET * acc
185
186 while 1:
187 f0 = -ET
188 g0 = 0
189 x2 = x**2
190 for i in range(1, N+1):
191 E[i] = math.sqrt(XM2[i]+x2*P2[i])
192 f0 += E[i]
193 g0 += P2[i]/E[i]
194 if abs(f0) <= accu:
195 break
196 n_iter += 1
197 if n_iter > itmax:
198 print("RAMBO WARNS: %s ITERATIONS DID NOT GIVE THE DESIRED ACCURACY = %s" \
199 %(n_iter , f0))
200 break
201 x=x-f0/(x*g0)
202 for i in range(1, N+1):
203 V[i] = x * P[(4,i)]
204 for k in range(1,4):
205 P[(k,i)] = x * P[(k,i)]
206 P[(4,i)] = E[i]
207
208
209 wt2 = 1.
210 wt3 = 0.
211 for i in range(1, N+1):
212 wt2 *= V[i]/E[i]
213 wt3 += V[i]**2/E[i]
214 wtm = (2.*N-3.)*math.log(x)+math.log(wt2/wt3*ET)
215
216
217 wt += wtm
218 if(wt < -180 and iwarn[3] < 5):
219 print(" RAMBO WARNS: WEIGHT = EXP(%s) MAY UNDERFLOW" % wt)
220 iwarn[3] += 1
221 if(wt > 174 and iwarn[4] > 5):
222 print(" RAMBO WARNS: WEIGHT = EXP(%s) MAY OVERFLOW" % wt)
223 iwarn[4] += 1
224
225
226 return P, wt
227
234