Skip to content

Commit 8d5fa78

Browse files
committed
refining angle defs in 2-3 scattering; adding mtrx elements for 2nu2gamma interaction; minor track length fixes in FluxBremIsotropic
1 parent 908f88b commit 8d5fa78

File tree

3 files changed

+137
-18
lines changed

3 files changed

+137
-18
lines changed

cross_section_mc.py

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,10 @@ class Scatter2to3MC:
252252
"""
253253
2 -> 3 scattering for general masses in fixed target frame
254254
Based on Byckling, Kajantie ch. V.4
255+
256+
ATTN: assumes particle A is at rest.
255257
"""
256-
def __init__(self, mtrx2: MatrixElement2to3, p1=LorentzVector(), p2=LorentzVector(), n_samples=1000):
258+
def __init__(self, mtrx2: MatrixElement2to3, p1=LorentzVector(), p2=LorentzVector(), n_samples=100):
257259
self.mtrx2 = mtrx2
258260

259261
self.ma = mtrx2.ma
@@ -274,6 +276,7 @@ def __init__(self, mtrx2: MatrixElement2to3, p1=LorentzVector(), p2=LorentzVecto
274276

275277
def cayley_det(self, x, y, z, u, v, w):
276278
# Gramm-Schmidt det but with invariants
279+
# Eq. 5.24 of Byckling, Kajantie
277280
return -0.5 * np.linalg.det([[0, 1, 1, 1, 1],
278281
[1, 0, v, x, z],
279282
[1, v, 0, u, y],
@@ -283,6 +286,9 @@ def cayley_det(self, x, y, z, u, v, w):
283286
def kallen(self, x, y, z):
284287
return np.power((x - y - z), 2) - 4*y*z
285288

289+
def flux_factor(self, s):
290+
return power(2*sqrt(self.kallen(s, self.ma**2, self.mb**2))*(2*pi)**5, -1)
291+
286292
def s2MaxMin(self, s):
287293
return (sqrt(s) - self.m1)**2, (self.m2 + self.m3)**2
288294

@@ -293,7 +299,7 @@ def t1MaxMin(self, s, s2):
293299
+ np.nan_to_num(sqrt(self.kallen(s, self.ma**2, self.mb**2)*self.kallen(s, s2, self.m1**2))))/(2*s)
294300

295301
def phase_space_heaviside(self, s, t1, s2):
296-
return np.heaviside(-np.nan_to_num(self.cayley_det(s, t1, s2, self.ma**2, self.mb**2, self.m1**2)), 0.0) \
302+
return np.heaviside(np.nan_to_num(-self.cayley_det(s, t1, s2, self.ma**2, self.mb**2, self.m1**2)), 0.0) \
297303
* np.heaviside(self.kallen(s, self.m1**2, s2), 0.0) \
298304
* np.heaviside(self.kallen(s2, self.m2**2, self.m3**2), 0.0)
299305

@@ -310,11 +316,30 @@ def s1_from_angle(self, phib, s, t1, s2, t2):
310316
[s-self.ma**2 + self.mb**2, s+s2-self.m1**2, 0.0]]) \
311317
+ 2*np.nan_to_num(sqrt(self.cayley_det(s,t1,s2,self.ma**2,self.mb**2,self.m1**2)*self.cayley_det(s2,t2,self.m3**2,t1,self.mb**2,self.m2**2)))*cos(phib))
312318

319+
def paR23(self, s, t1, s2):
320+
return sqrt(((s + t1 - self.mb**2 - self.m1**2)/(2*sqrt(s2)))**2 - self.ma**2)
321+
322+
def pbR23(self, s2, t1):
323+
return sqrt(self.kallen(s2, self.mb**2, t1)/s2) / 2
324+
325+
def p1R23(self, s, s2):
326+
e1_cm = (s + self.m1**2 - s2)/(2*sqrt(s))
327+
return np.sqrt(e1_cm**2 - self.m1**2)
328+
329+
def sinTheta_b1(self, s, t1, s2):
330+
# R23 frame
331+
return -4 * s2 * self.cayley_det(s, t1, s2, self.ma**2, self.mb**2, self.m1**2) \
332+
/ (self.kallen(s2, self.mb**2, t1)*self.kallen(s, s2, self.m1**2))
333+
334+
def cosTheta_ab(self, s, s2, t1):
335+
sinTheta_b1 = self.sinTheta_b1(s, t1, s2)
336+
cosTheta_b1 = sqrt(1 - sinTheta_b1**2)
337+
return (self.p1R23(s, s2)*self.pbR23(s2, t1)*cosTheta_b1 - self.pbR23(s2, t1)**2) / (self.pbR23(s2, t1)*self.paR23(s, t1, s2))
338+
313339
def dsigma_ds2dt1dOmega3(self, s, s2, t1, cosThetab3, phib):
314340
t2 = self.t2_from_angle(cosThetab3, t1, s2)
315341
s1 = self.s1_from_angle(phib, s, t1, s2, t2)
316-
return pi * self.phase_space_heaviside(s, t1, s2) * self.mtrx2(s, s2, t1, s1, t2) \
317-
* power(2*sqrt((s - (self.ma + self.mb)**2)*(s - (self.ma - self.mb)**2)), -1) \
342+
return pi * self.phase_space_heaviside(s, t1, s2) * self.mtrx2(s, s2, t1, s1, t2) * self.flux_factor(s) \
318343
* np.nan_to_num(sqrt(self.kallen(s, self.ma**2, self.mb**2)/self.kallen(s2, self.m2**2, self.m3**2)))/(16*s2)
319344

320345
def r23_velocity(self, s2, t1):
@@ -364,23 +389,76 @@ def simulate_particle1(self, s):
364389
t1_rnd = np.random.uniform(t1Min, t1Max, self.n_samples)
365390
cos_rnd = np.random.uniform(-1, 1, self.n_samples)
366391
phi_rnd = np.random.uniform(0.0, 2*pi, self.n_samples)
392+
393+
print("t1 min, max = ", t1Min, t1Max)
394+
print("s2 min, max = ", s2Min, s2Max)
367395

368396
mc_volume = (t1Max - t1Min)*(s2Max - s2Min)*4*pi / self.n_samples
369397

370398
# Get particle 1's CM spectra
371399
for i in range(self.n_samples):
400+
if self.phase_space_heaviside(s, t1_rnd[i], s2_rnd[i]) < 1.0:
401+
continue
402+
372403
weights = self.dsigma_ds2dt1dOmega3(s, s2_rnd[i], t1_rnd[i], cos_rnd[i], phi_rnd[i])
373404
e1_cm = (s + self.m1**2 - s2_rnd[i])/(2*sqrt(s))
374405
p1_cm = np.sqrt(e1_cm**2 - self.m1**2)
375406
theta_b1_cm = arcsin(sqrt(-4*s2_rnd[i]*self.cayley_det(s, t1_rnd[i], s2_rnd[i], self.ma**2, self.mb**2, self.m1**2) \
376407
/ (self.kallen(s2_rnd[i], self.mb**2, t1_rnd[i])*self.kallen(s, s2_rnd[i], self.m1**2))))
377408
lorentz_vector_p1_cm = LorentzVector(e1_cm, p1_cm*sin(theta_b1_cm), 0.0, p1_cm*cos(theta_b1_cm))
378-
v_cm_to_lab = self.r23_velocity(s2_rnd[i], t1_rnd[i])
379-
lorentz_vector_p1_lab = lorentz_boost(lorentz_vector_p1_cm, v_cm_to_lab)
409+
410+
# Boost to lab frame: use pa velocity assuming pa is at rest
411+
pa_R23 = self.paR23(s, t1_rnd[i], s2_rnd[i])
412+
ea_R23 = sqrt(pa_R23**2 + self.ma**2)
413+
cosTheta_ab_R23 = self.cosTheta_ab(s, s2_rnd[i], t1_rnd[i])
414+
va_R23_3vec = Vector3(-pa_R23*sqrt(1-cosTheta_ab_R23**2)/ea_R23, 0.0, -pa_R23*cosTheta_ab_R23/ea_R23)
415+
416+
#v_cm_to_lab = self.r23_velocity(s2_rnd[i], t1_rnd[i])
417+
lorentz_vector_p1_lab = lorentz_boost(lorentz_vector_p1_cm, va_R23_3vec)
380418
self.p1_lab_4vectors.append(lorentz_vector_p1_lab)
381419
self.p1_lab_energies.append(lorentz_vector_p1_lab.p0)
420+
#print("dsigma = {}, CM energy = {}, Lab energy = {}".format(weights, lorentz_vector_p1_cm.p0, lorentz_vector_p1_lab.p0))
382421
self.p1_lab_angles.append(lorentz_vector_p1_lab.theta())
383422
self.dsigma.append(weights * mc_volume)
423+
424+
def simulate_particle1_phase_space_sampled(self, s):
425+
s2Max, s2Min = self.s2MaxMin(s)
426+
427+
s2_grid = np.linspace(s2Min, s2Max, self.n_samples)
428+
s2_points = (s2_grid[1:] + s2_grid[:-1])/2
429+
delta_s2 = s2_grid[1] - s2_grid[0]
430+
431+
cos_rnd = np.random.uniform(-1, 1, self.n_samples)
432+
phi_rnd = np.random.uniform(0.0, 2*pi, self.n_samples)
433+
434+
# Get particle 1's CM spectra
435+
for s2 in s2_points:
436+
t1Max, t1Min = self.t1MaxMin(s, s2)
437+
t1_rnd = np.random.uniform(t1Min, t1Max, self.n_samples)
438+
mc_volume = (t1Max - t1Min)*delta_s2*4*pi / self.n_samples
439+
for i, t1 in enumerate(t1_rnd):
440+
if self.phase_space_heaviside(s, t1, s2) < 1.0:
441+
continue
442+
443+
weights = self.dsigma_ds2dt1dOmega3(s, s2, t1, cos_rnd[i], phi_rnd[i])
444+
e1_cm = (s + self.m1**2 - s2)/(2*sqrt(s))
445+
p1_cm = np.sqrt(e1_cm**2 - self.m1**2)
446+
theta_b1_cm = arcsin(sqrt(-4*s2*self.cayley_det(s, t1, s2, self.ma**2, self.mb**2, self.m1**2) \
447+
/ (self.kallen(s2, self.mb**2, t1)*self.kallen(s, s2, self.m1**2))))
448+
lorentz_vector_p1_cm = LorentzVector(e1_cm, p1_cm*sin(theta_b1_cm), 0.0, p1_cm*cos(theta_b1_cm))
449+
450+
# Boost to lab frame: use pa velocity assuming pa is at rest
451+
pa_R23 = self.paR23(s, t1, s2)
452+
ea_R23 = sqrt(pa_R23**2 + self.ma**2)
453+
cosTheta_ab_R23 = self.cosTheta_ab(s, s2, t1)
454+
va_R23_3vec = Vector3(-pa_R23*sqrt(1-cosTheta_ab_R23**2)/ea_R23, 0.0, -pa_R23*cosTheta_ab_R23/ea_R23)
455+
456+
lorentz_vector_p1_lab = lorentz_boost(lorentz_vector_p1_cm, va_R23_3vec)
457+
self.p1_lab_4vectors.append(lorentz_vector_p1_lab)
458+
self.p1_lab_energies.append(lorentz_vector_p1_lab.p0)
459+
self.p1_lab_angles.append(lorentz_vector_p1_lab.theta())
460+
self.dsigma.append(weights * mc_volume)
461+
384462

385463

386464

fluxes.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -293,22 +293,23 @@ def simulate_single(self, electron):
293293
self.axion_energy.extend(ea_rnd)
294294
self.axion_flux.extend(el_wgt * diff_br)
295295

296-
def simulate(self):
296+
def simulate(self, use_track_length=False):
297297
self.axion_energy = []
298298
self.axion_flux = []
299299
self.scatter_axion_weight = []
300300
self.decay_axion_weight = []
301301

302-
"""
303-
ep_min = max((self.ma**2 - M_E**2)/(2*M_E), M_E)
304-
for i, el in enumerate(self.electron_flux):
305-
t_depth = np.random.uniform(0.0, 5.0)
306-
new_energy = np.random.uniform(ep_min, el[0])
307-
flux_weight = self.electron_flux_attenuated(t_depth, el[0], new_energy) * 5.0 * (el[0] - ep_min)
308-
self.simulate_single([new_energy, flux_weight])
309-
"""
310-
for i, el in enumerate(self.electron_flux):
311-
self.simulate_single(el)
302+
if use_track_length:
303+
ep_min = max((self.ma**2 - M_E**2)/(2*M_E), M_E)
304+
for i, el in enumerate(self.electron_flux):
305+
t_depth = np.random.uniform(0.01, 5.0)
306+
new_energy = np.random.uniform(ep_min, el[0])
307+
flux_weight = self.electron_flux_attenuated(t_depth, el[0], new_energy) * 5.0 * (el[0] - ep_min)
308+
self.simulate_single([new_energy, el[1] * flux_weight])
309+
310+
else:
311+
for i, el in enumerate(self.electron_flux):
312+
self.simulate_single(el)
312313

313314
def propagate(self, new_coupling=None):
314315
if new_coupling is not None:

matrix_element.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,4 +746,44 @@ def __call__(self, s, s2, t1, s1, t2, gae=1.0):
746746
m = self.m2
747747
M = self.ma
748748
prefactor = self.ffp(t1) * self.ff2(sqrt(abs(t1))) * power(gae * 4*pi*ALPHA, 2.0) / power(t2 * (m**2-t2) * (m**2+mA**2-s2-t2+t1), 2)
749-
return prefactor * 4*(m**4*(2*M**4*(mA**2+t1)+2*M**2*(3*mA**4+mA**2*(3*t1-2*(s+s2))-t1*(2*s+s2)+s2**2)+2*(mA**3-mA*s)**2+t1*(mA**4+2*mA**2*(s2-s)+2*s**2-2*s*s2+s2**2)+2*t1**2*(s-s2)+t1**3)+m**2*(2*M**4*((2*mA**2+t1)*(mA**2-s2+t1)-2*t2*(mA**2+t1))+2*M**2*((mA**2-s2+t1)*(3*mA**4-2*mA**2*(s+s1+s2-t1)-t1*(2*s+s2)+s2**2)+2*t2*(-2*mA**4+mA**2*(2*s+s2-2*t1)+2*s*t1+s2*(t1-s2)))+mA**6*(t1-4*s1)+mA**4*(4*s*(s1+t2)+4*s1*s2-4*s1*t1-s2*t1-4*s2*t2+3*t1**2+2*t1*t2)+mA**2*(2*s**2*(t1-2*t2)-2*s*(2*s1+t1)*(s2-t1)+4*s*s2*t2+t1*(s2**2-4*s2*(t1+t2)+3*t1**2))+t1*(2*s**2+2*s*(t1-s2)+(s2-t1)**2)*(-s2+t1-2*t2))+2*M**4*(mA**2-s2+t1-t2)*(mA**4-mA**2*(s2-t1+t2)-t1*t2)-2*M**2*(2*mA**2*s1*(mA**2-s2+t1)**2+t2*(mA**2-s2+t1)*(mA**4-2*mA**2*(s+s1)-t1*(2*s+s2)+s2**2)-t2**2*(mA**4+mA**2*(t1-2*s)-t1*(2*s+s2)+s2**2))+mA**2*(2*s1**2+2*s1*t1+t1**2)*(mA**2-s2+t1)**2-t2*(mA**2-s2+t1)*(mA**4*t1+2*mA**2*(2*s*s1-2*s1*s2+2*s1*t1+t1**2)+t1*(2*s**2+2*s*(t1-s2)+(s2-t1)**2))+t2**2*(mA**4*t1+2*mA**2*(t1*(s-s2)+(s-s2)**2+t1**2)+t1*(2*s**2+2*s*(t1-s2)+(s2-t1)**2)))
749+
return prefactor * 4*(m**4*(2*M**4*(mA**2+t1)+2*M**2*(3*mA**4+mA**2*(3*t1-2*(s+s2))-t1*(2*s+s2)+s2**2)+2*(mA**3-mA*s)**2+t1*(mA**4+2*mA**2*(s2-s)+2*s**2-2*s*s2+s2**2)+2*t1**2*(s-s2)+t1**3)+m**2*(2*M**4*((2*mA**2+t1)*(mA**2-s2+t1)-2*t2*(mA**2+t1))+2*M**2*((mA**2-s2+t1)*(3*mA**4-2*mA**2*(s+s1+s2-t1)-t1*(2*s+s2)+s2**2)+2*t2*(-2*mA**4+mA**2*(2*s+s2-2*t1)+2*s*t1+s2*(t1-s2)))+mA**6*(t1-4*s1)+mA**4*(4*s*(s1+t2)+4*s1*s2-4*s1*t1-s2*t1-4*s2*t2+3*t1**2+2*t1*t2)+mA**2*(2*s**2*(t1-2*t2)-2*s*(2*s1+t1)*(s2-t1)+4*s*s2*t2+t1*(s2**2-4*s2*(t1+t2)+3*t1**2))+t1*(2*s**2+2*s*(t1-s2)+(s2-t1)**2)*(-s2+t1-2*t2))+2*M**4*(mA**2-s2+t1-t2)*(mA**4-mA**2*(s2-t1+t2)-t1*t2)-2*M**2*(2*mA**2*s1*(mA**2-s2+t1)**2+t2*(mA**2-s2+t1)*(mA**4-2*mA**2*(s+s1)-t1*(2*s+s2)+s2**2)-t2**2*(mA**4+mA**2*(t1-2*s)-t1*(2*s+s2)+s2**2))+mA**2*(2*s1**2+2*s1*t1+t1**2)*(mA**2-s2+t1)**2-t2*(mA**2-s2+t1)*(mA**4*t1+2*mA**2*(2*s*s1-2*s1*s2+2*s1*t1+t1**2)+t1*(2*s**2+2*s*(t1-s2)+(s2-t1)**2))+t2**2*(mA**4*t1+2*mA**2*(t1*(s-s2)+(s-s2)**2+t1**2)+t1*(2*s**2+2*s*(t1-s2)+(s2-t1)**2)))
750+
751+
752+
753+
754+
class M2DMFourFermi(MatrixElement2):
755+
def __init__(self, mDM=1.0e3):
756+
super().__init__(M_P, mDM, mDM, M_P)
757+
self.mPsi = mDM
758+
759+
def __call__(self, s, t, lamByMx=0.1):
760+
return power(lamByMx, 4) * ((s+t)**2 - 4*(M_P**2 - self.mPsi**2)**2)
761+
762+
763+
764+
class M2NeutrinoBrem(MatrixElement2to3):
765+
def __init__(self, mf=1.0, mi=0.0, MTarget=M_P, z=6, LamScale=1.0e6):
766+
super().__init__(MTarget, mi, 0.0, mf, MTarget)
767+
self.mf = mf
768+
self.mi = mi
769+
self.M = MTarget
770+
self.ff = AtomicElasticFF(z)
771+
self.Lam = LamScale
772+
"""
773+
def __call__(self, s, s2, t1, s1, t2):
774+
prefactor = self.ff(sqrt(abs(-2*self.M**2+s-s1+t2)))*(2*pi*ALPHA)/(self.Lam**6 * power(-2*self.M**2+s-s1+t2, 2))
775+
return prefactor*abs((self.M**2+2*self.mf*self.mi-s2+t1-t2)*\
776+
(1/8*(s1-self.mf**2)*(-(self.mf**2+s-s1-s2)*(self.M**2+self.mi**2-s+s1+t1-t2)+(self.M**2-t1)\
777+
*(2*self.M**2+self.mf**2+self.mi**2-s2-t2)+4*self.M**2*(self.M**2-s+s2-t1)) \
778+
+1/8*(-self.M**2+s-s2+t1)*((self.mf**2+s-s1-s2)*(self.M**2+self.mi**2-s+s1+t1-t2) \
779+
-(self.M**2-t1)*(2*self.M**2+self.mf**2+self.mi**2-s2-t2)) \
780+
+1/4*self.mi*(self.M**2-t1)*(self.mf**2+s-s1-s2)+1/4*(self.M**2-t1)\
781+
*(self.M**2-s2+t1-t2)*(self.mf**2+s-s1-s2)+1/4*self.mf**2 \
782+
*(self.M**2-t1)*(self.mf**2+s-s1-s2)+1/4*self.M**2*(self.mf**2-s1)**2+1/4*self.M**2*(self.M**2-s+s2-t1)**2))
783+
"""
784+
def __call__(self, s, s2, t1, s1, t2):
785+
prefactor = self.ff(sqrt(abs(-2*self.M**2+s-s1+t2)))*(2*pi*ALPHA)/(self.Lam**6 * power(-2*self.M**2+s-s1+t2, 2))
786+
return prefactor*abs((self.M**2 - s2 + t1 - t2)*(2*self.M**2 * (2*self.mf**2*(2*s - 2*(s1 + s2) + t1) + 2*self.mf**4 + 2*s**2 - \
787+
4*s*(s1 + s2) + 3*s*t1 + 2*s1**2 + 4*s1*s2 - 3*s1*t1 + 2*s2**2 - \
788+
2*s2*t1 + 2*t1**2 + t1*t2) - self.M**4 * (4*self.mf**2 + 5*s - 5*s1 - 4*s2 + 8*t1 + t2) + \
789+
4*self.M**6 - (s - s1 + t2)*((self.mf**2 + s - s1 - s2)**2 + t1**2)))

0 commit comments

Comments
 (0)