def dRdE_nu(E_r,t,sol,E_nu,Flux,Nuc): N = Nuc.NumberOfNeutrons Z = Nuc.NumberOfProtons Q_W = 1.0*N-(1-4.0*sinTheta_Wsq)*Z # weak nuclear hypercharge m_N_GeV = 0.93141941*(N+Z) # nucleus mass in GeV m_N_keV = m_N_GeV*1.0e6 # nucleus mass in keV dRdE = zeros(shape=shape(E_r)) FF = LabFuncs.FormFactorHelm(E_r,N+Z)**2.0 ne = size(E_r) if Flux[1]>0.0: for i in range(0,ne): diff_sigma = (G_F_GeV**2.0 /(4.0*pi))*(Q_W**2.0)*m_N_GeV*(1.0 \ -(m_N_keV*E_r[i])/(2.0*(E_nu*1000.0)**2.0))*\ (0.197e-13)**2.0*(1.0e-6)*1000.0/(1.0*N+1.0*Z)*(N_A) diff_sigma[diff_sigma<0.0] = 0.0 dRdE[i] = trapz(diff_sigma*Flux*FF[i],x=E_nu) else: for i in range(0,ne): diff_sigma = (G_F_GeV**2.0 /(4.0*pi))*(Q_W**2.0)*m_N_GeV*(1.0 \ -(m_N_keV*E_r[i])/(2.0*(E_nu[0]*1000.0)**2.0))*\ (0.197e-13)**2.0*(1.0e-6)*1000.0/(1.0*N+1.0*Z)*(N_A) if diff_sigma>0: dRdE[i] = diff_sigma*Flux[0]*E_nu[0] # for monochromatic nu's if sol: fMod = LabFuncs.EarthSunDistanceMod(t) else: fMod = 1.0 # Convert into /ton/year/keV dRdE = fMod*dRdE*(365.0*3600.0*24.0*1000.0) return dRdE
def SpeedDist_Isotropic(v,day=67.0,v_LSR=Params.SHMpp.RotationSpeed,\ sig=Params.SHMpp.Dispersion,\ v_esc=Params.SHMpp.EscapeSpeed,\ v_shift=array([0.0,0.0,0.0]),GravFocus=False,\ EscapeSpeed=True): ## Isotropic speed distribution # v = speeds (in km/s) # v_LSR = Local standard of rest # sig = 1d dispersion # v_esc = escape speed # v_shift = any shift to v_lab needed (usually the stream velocity) # GravFocus = whether to calculate gravfocus or not # EscpaeSpeed = whether to implement v_esc or not (i.e. v_esc=inf) # Analytic form for the speed distribution: v_lab = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR)-v_shift v_e = sqrt(sum(v_lab**2.0)) v0 = sig*sqrt(2.0) N_esc = Nesc_Isotropic(sig,v_esc) fv1 = (1.0/(N_esc*sqrt(2*pi)))*(v/(v_e*sig))\ *(exp(-(v**2.0+v_e**2.0-2.0*v*v_e)/(2*sig**2.0))\ -exp(-(v**2.0+v_e**2.0+2.0*v*v_e)/(2*sig**2.0)))\ *((v)<(v_esc+v_e)) f1 = (1.0/(N_esc*sqrt(2*pi)))*(v/(v_e*sig))\ *(exp(-(v**2.0+v_e**2.0-2.0*v*v_e)/(2*sig**2.0))\ -exp(-(v**2.0+v_e**2.0+2.0*v*v_e)/(2*sig**2.0))) f2 = (1.0/(N_esc*sqrt(2*pi)))*(v/(v_e*sig))\ *(exp(-(v**2.0+v_e**2.0-2.0*v*v_e)/(2*sig**2.0))\ -(2/sqrt(pi))*exp(-v_esc**2.0/(2*sig**2.0))) fv1[v<(v_esc-v_e)] = f1[v<(v_esc-v_e)] fv1[v>(v_esc-v_e)] = f2[v>(v_esc-v_e)] fv1 /= trapz(fv1,v) # Turn off escape if needed if not EscapeSpeed: N_esc = 1.0 v_esc = 1000.0 # Can do analytic grav focusing calculation which uses a pertubative result # currently not used in the paper since every example uses the function # following this one. if GravFocus: nvals = size(v) fvJ = zeros(shape=nvals) # Loop over speeds for i in range(0,nvals): vv = v[i] voff2 = (vv*sqrt(1-C**2)*cos(P)+v_lab[0])**2\ + (vv*sqrt(1-C**2.0)*sin(P)+v_lab[1])**2.0\ + (vv*C+v_lab[2])**2 # speed fv3 = vv**2.0*(1.0/(sqrt(pi)*pi))*(1.0/v0**3)*exp(-voff2/v0**2) fJ = fv3*LabFuncs.GravFocusAngles(vv,C,P,day,sig=sig) fvJ[i] = dth*dph*sum(sum(fJ)) fv1 += fvJ return fv1
def SpeedDist_Triaxial_alt(v,day,sig3,v_LSR=233.0,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0]),GravFocus=False): # Exactly the same as previous function but uses a faster discretisation sigr = sig3[0] sigphi = sig3[1] sigz = sig3[2] beta = 1.0-(sigphi**2.0+sigz**2.0)/(2*sigr**2.0) if beta>0.0: N_esc = Nesc_Triaxial(sigr,sigphi,beta,v_esc) elif beta==0.0: N_esc = Nesc_Isotropic(sigr,v_esc) else: N_esc = 1.0 v_e = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR) N = 1.0/(N_esc*(2*pi)**(1.5)*sigr*sigphi*sigz) n = size(v) fv1 = zeros(shape=n) if GravFocus==False: v_off = v_e-v_shift vv_e = sqrt(sum(v_off**2.0)) for i in range(0,n): v1 = v[i] vr = v1*x_pix[:,0]+v_off[0] vphi = v1*x_pix[:,1]+v_off[1] vz = v1*x_pix[:,2]+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<(v_esc)) fv1[i] = (v1**2.0)*sum(F)*dpix else: v_off = LabFuncs.v_pec+array([0.0,v_LSR,0.0])-v_shift vv_e = sqrt(sum(v_off**2.0)) for i in range(0,n): v1 = v[i] vr,vphi,vz = LabFuncs.v_infinity_alt(v1*x_pix,day) vr += v_off[0] vphi += v_off[1] vz += v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<(v_esc)) fv1[i] = (v1**2.0)*sum(F)*dpix return fv1
def dRdEdO_wimp(E,t,DM,HaloModel=Params.SHM,Nuc=Params.Ar40,\ Loc=Params.GranSasso,CygnusTracking=False): E_r = sqrt(E[:, 0]**2 + E[:, 1]**2 + E[:, 2]**2) # Recoil energy x = zeros(shape=shape(E)) x[:, 0] = E[:, 0] / E_r # Recoil direction x[:, 1] = E[:, 1] / E_r x[:, 2] = E[:, 2] / E_r # relevant constants A = Nuc.MassNumber # mass number of nucleus m_chi = DM.Mass mu_p = 1.0e6 * m_chi * m_p_keV / (1.0e6 * m_chi + m_p_keV) sigma_p = DM.SICrossSection sig_v = HaloModel.Dispersion v_esc = HaloModel.EscapeSpeed rho_0 = HaloModel.Density N_esc = HaloModel.Normalisation FF = LabFuncs.FormFactorHelm(E_r, A)**2.0 v_min = MinimumWIMPSpeed(E_r, A, m_chi) R0 = (c_cm * c_cm) * ((rho_0 * 1.0e6 * A * A * sigma_p) / (4 * pi * m_chi * GeV_2_kg * mu_p * mu_p)) # Calculate v_lab ne = size(E_r) nt = size(t) dR = zeros(shape=(size(E_r))) v_lab = zeros(shape=(size(E_r), 3)) for i in range(0, nt): v_lab[i, :] = LabFuncs.LabVelocity(t[i], Loc, HaloModel.RotationSpeed) # Just put vlab towards north pole for cygnus tracking experiment: if CygnusTracking == True: for i in range(0, nt): v_lab[i, :] = array([0.0, 0.0, sqrt(sum(v_lab[i, :]**2.0))]) # recoil projection vlabdotq = (x[:, 0] * v_lab[:, 0] + x[:, 1] * v_lab[:, 1] + x[:, 2] * v_lab[:, 2]) # Radon transform fhat = zeros(shape=shape(E_r)) fhat[((v_min+vlabdotq)<(v_esc))] = (1/(N_esc*sqrt(2*pi*sig_v**2.0)))\ *(exp(-(v_min[((v_min+vlabdotq)<(v_esc))]\ +vlabdotq[((v_min+vlabdotq)<(v_esc))])\ **2.0/(2*sig_v**2.0))\ -exp(-v_esc**2.0/(2*sig_v**2.0))) fhat = fhat / (1000.0 * 100.0) # convert to cm^-1 s # Compute rate = (Rate amplitude * radon trans. * form factor) dR = R0 * fhat * FF # correct for form factor dR = dR * seconds2year * 1000.0 # convert to per ton-year return dR
def dRdE_wimp(E_r,t,DM,\ HaloModel=Params.SHM,Nuc=Params.Ar40,Loc=Params.GranSasso): # relevant constants A = Nuc.MassNumber # mass number of nucleus m_chi = DM.Mass mu_p = 1.0e6 * m_chi * m_p_keV / (1.0e6 * m_chi + m_p_keV) sigma_p = DM.SICrossSection v_0 = sqrt(2.0) * HaloModel.Dispersion v_esc = HaloModel.EscapeSpeed rho_0 = HaloModel.Density N_esc = HaloModel.Normalisation FF = LabFuncs.FormFactorHelm(E_r, A)**2.0 v_min = MinimumWIMPSpeed(E_r, A, m_chi) R0 = (c_cm * c_cm) * ((rho_0 * 1.0e6 * A * A * sigma_p) / (2 * m_chi * GeV_2_kg * mu_p * mu_p)) # init ne = size(E_r) nt = size(t) dR = zeros(shape=ne) gvmin = zeros(ne) # Mean inverse speed x = v_min / v_0 z = v_esc / v_0 if t[0] == t[-1]: v_e = norm(LabFuncs.LabVelocity(t[0], Loc, HaloModel.RotationSpeed)) y = v_e / v_0 gvmin[(x < abs(y - z)) & (z < y)] = (1.0 / (v_0 * y)) else: v_e = zeros(shape=ne) for i in range(0, nt): v_e[i] = norm( LabFuncs.LabVelocity(t[i], Loc, HaloModel.RotationSpeed)) y = v_e / v_0 g1 = (1.0 / (v_0 * y)) gvmin[(x < abs(y - z)) & (z < y)] = g1[(x < abs(y - z)) & (z < y)] g2 = (1.0 / (2.0 * N_esc * v_0 * y)) * (erf(x + y) - erf(x - y) - (4.0 / sqrt(pi)) * y * exp(-z**2)) g3 = (1.0 / (2.0 * N_esc * v_0 * y)) * (erf(z) - erf(x - y) - (2.0 / sqrt(pi)) * (y + z - x) * exp(-z**2)) gvmin[(x < abs(y - z)) & (z > y)] = g2[(x < abs(y - z)) & (z > y)] gvmin[(abs(y - z) < x) & (x < (y + z))] = g3[(abs(y - z) < x) & (x < (y + z))] gvmin[(y + z) < x] = 0.0 gvmin = gvmin / (1000.0 * 100.0) # convert to cm^-1 s # Compute rate = (Rate amplitude * gmin * form factor) dR = R0 * gvmin * FF dR = dR * seconds2year * 1000.0 # convert to per ton-year return dR
def fhat_Isotropic(v_min,x,day,v_LSR=233.0,sig=164.75,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0])): # Radon transform: the directional halo integral for isotropic Gaussian # v_min = min speed again # x = array recoil vectors # Important: RECOIL VECTOR x JUST NEEDS TO BE IN SAME COORDINATES AS v_lab v_lab = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR)-v_shift v0 = sig*sqrt(2.0) N_esc = Nesc_Isotropic(sig,v_esc) # dot product of v_lab and recoil vectors vlabdotq = (x[:,0]*v_lab[0]+x[:,1]*v_lab[1]+x[:,2]*v_lab[2]) # recoil projection fhat = zeros(shape=size(vlabdotq)) fhat[((v_min+vlabdotq)<(v_esc))] = (1/(N_esc*sqrt(2*pi*sig**2.0)))\ *(exp(-(v_min+vlabdotq[((v_min+vlabdotq)<(v_esc))])\ **2.0/(2*sig**2.0))\ -exp(-v_esc**2.0/(2*sig**2.0))) # needs to be divided by 2*pi, then the WIMP rate formula is independent of # which halo integral is used fhat /= 2*pi return fhat
def VelocityDist_Isotropic(v,day,v_LSR=233.0,sig=164.75,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0]),GravFocus=False,\ EscapeSpeed=True): ## Isotropic velocity distribution # v = velocities (in galactic cylindrical coordinates) # v_LSR = Local standard of rest # sig = 1d dispersion # v_esc = escape speed # v_shift = any shift to v_lab needed (usually the stream velocity) # GravFocus = whether to calculate gravfocus or not # EscpaeSpeed = whether to implement v_esc or not (i.e. v_esc=inf) # lab velocity v_lab = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR)-v_shift v0 = sig*sqrt(2.0) # denominator in exponent N_esc = Nesc_Isotropic(sig,v_esc) # normalisation vr = v[:,0] # radial comp. vphi = v[:,1] # azimuthal comp. vz = v[:,2] # vertical comp. V = sqrt((vr+v_lab[0])**2.0+(vphi+v_lab[1])**2.0+(vz+v_lab[2])**2.0) # speed # Now compute value of distribution fv3 = (1.0/(N_esc*sqrt(2*pi)*sig**3.0)*\ exp(-((vr+v_lab[0])**2.0\ +(vz+v_lab[2])**2.0\ +(vphi+v_lab[1])**2.0)/(2*sig**2.0)))*(V<v_esc) return fv3
def fhat_Triaxial(v_min,x,day,sig3,v_LSR=233.0,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0])): # Same as previous but for a Triaxial gaussian v_lab = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR)-v_shift sigr = sig3[0] sigphi = sig3[1] sigz = sig3[2] # Normalisation beta = 1.0-(sigphi**2.0+sigz**2.0)/(2*sigr**2.0) if beta>0.0: N_esc = Nesc_Triaxial(sigr,sigphi,beta,v_esc) else: N_esc = 1.0 vlabdotq = (x[:,0]*v_lab[0]+x[:,1]*v_lab[1]+x[:,2]*v_lab[2]) # recoil projection qsq = (x[:,0]*sigr)**2.0 + (x[:,1]*sigphi)**2.0 + (x[:,2]*sigz)**2.0 fhat = zeros(shape=size(vlabdotq)) mask = ((v_min+vlabdotq)<(v_esc)) fhat[mask] = (1.0/(N_esc*sqrt(2*pi*qsq[mask])))*\ (exp(-(v_min+vlabdotq[mask])**2.0/(2*qsq[mask]))-\ exp(-v_esc**2.0/(2*qsq[mask]))) fhat /= 2*pi return fhat
def dRdEdO_wimp(E, t, DM, HaloModel, Nuc, Loc): E_r = sqrt(E[:, 0]**2 + E[:, 1]**2 + E[:, 2]**2) # Recoil energy x = zeros(shape=shape(E)) x[:, 0] = E[:, 0] / E_r # Recoil direction x[:, 1] = E[:, 1] / E_r x[:, 2] = E[:, 2] / E_r # relevant constants A = Nuc.MassNumber # mass number of nucleus m_chi = DM.Mass mu_p = 1.0e6 * m_chi * m_p / (1.0e6 * m_chi + m_p) sigma_p = DM.SICrossSection sig_v = HaloModel.Dispersion v_esc = HaloModel.EscapeSpeed rho_0 = HaloModel.Density N_esc = HaloModel.Normalisation FF = LabFuncs.FormFactorHelm(E_r, A)**2.0 v_min = MinimumWIMPSpeed(E_r, A, m_chi) R0 = (c_cm * c_cm) * ((rho_0 * 1.0e6 * A * A * sigma_p) / (4 * pi * m_chi * GeV_2_kg * mu_p * mu_p)) # init ne = size(E_r) nt = size(t) dR = zeros(shape=(size(E_r))) v_lab = zeros(shape=(size(E_r), 3)) for i in range(0, nt): v_lab[i, :] = LabFuncs.LabVelocity(t[i], Loc, HaloModel) vlabdotq = (x[:, 0] * v_lab[:, 0] + x[:, 1] * v_lab[:, 1] + x[:, 2] * v_lab[:, 2]) # recoil projection # Radon transform fhat = zeros(shape=shape(E_r)) fhat[((v_min+vlabdotq)<(v_esc))] = (1/(N_esc*sqrt(2*pi*sig_v**2.0)))\ *(exp(-(v_min[((v_min+vlabdotq)<(v_esc))]\ +vlabdotq[((v_min+vlabdotq)<(v_esc))])\ **2.0/(2*sig_v**2.0))\ -exp(-v_esc**2.0/(2*sig_v**2.0))) fhat = fhat / (1000.0 * 100.0) # convert to cm^-1 s # Compute rate = (Rate amplitude * radon trans. * form factor) dR = R0 * fhat * FF # correct for form factor dR = dR * 3600 * 24 * 365 * 1000.0 # convert to per ton-year return dR
def dRdEe_nu(E_r, t, sol, E_nu, Flux, Atom, flav): N = Atom.NumberOfNeutrons Z = Atom.NumberOfProtons Q_W = 1.0 * N - (1 - 4.0 * sinTheta_Wsq) * Z # weak nuclear hypercharge m_N_GeV = 0.93141941 * (N + Z) # nucleus mass in GeV m_N_keV = m_N_GeV * 1.0e6 # nucleus mass in keV m_e_GeV = 5.109989461e-4 ne = size(E_r) if sol: fMod = LabFuncs.EarthSunDistanceMod(t) else: fMod = 1.0 gV = array([ 2 * sinTheta_Wsq + 0.5, 2 * sinTheta_Wsq - 0.5, 2 * sinTheta_Wsq - 0.5, 2 * sinTheta_Wsq + 0.5, 2 * sinTheta_Wsq - 0.5, 2 * sinTheta_Wsq - 0.5 ]) gA = array([0.5, -0.5, -0.5, -0.5, 0.5, 0.5]) T = E_r / 1000 # MeV Tmax = 2 * E_nu**2.0 / (2 * E_nu + m_e_GeV * 1000) dR = 0.0 for ii in arange(0, 6)[flav > 0]: dRdE = zeros(shape=ne) As = (gV[ii] + gA[ii])**2.0 Bs = (gV[ii] - gA[ii])**2.0 Cs = (gA[ii]**2.0 - gV[ii]**2.0) if Flux[1] > 0.0: for i in range(0, ne): diff_sigma = (G_F_GeV**2.0 * m_e_GeV / (2 * pi)) * (As + Bs * (1 - T[i] / E_nu)**2.0 + Cs * 1000 * m_e_GeV * T[i] / E_nu**2.0) diff_sigma *= (0.197e-13)**2.0 * (1.0e-6) * 1000.0 / ( 1.0 * N + 1.0 * Z) * (N_A) diff_sigma[T[i] > Tmax] = 0.0 dRdE[i] = trapz(diff_sigma * Flux, x=E_nu) else: diff_sigma = (G_F_GeV**2.0 * m_e_GeV / (2 * pi)) * (As + Bs * (1 - T / E_nu[0])**2.0 + Cs * 1000 * m_e_GeV * T / E_nu[0]**2.0) diff_sigma *= (0.197e-13)**2.0 * (1.0e-6) * 1000.0 / ( 1.0 * N + 1.0 * Z) * (N_A) diff_sigma[T > Tmax[0]] = 0.0 dRdE = diff_sigma * Flux[0] * E_nu[0] * ( diff_sigma > 0.0) # for monochromatic nu's # Convert into /ton/year/keV dRdE = fMod * dRdE * (365.0 * 3600.0 * 24.0 * 1000.0) dRdE = dRdE * Z * flav[ii] dR += dRdE return dR
def MaxWIMPEnergy(A,m_chi,\ v_lab=LabFuncs.LabVelocitySimple(67.0),v_esc=Params.SHM.EscapeSpeed): # A = nucleus mass number # v_lab = Lab velocity in km/s # m_chi = Wimp mass in GeV # v_esc = Escape speed in km/s m_N = m_p_keV * A mu_N = 1.0e6 * m_N * m_chi / (1.0e6 * m_chi + m_N) E_max_lim = 2.0 * mu_N * mu_N * 2.0 * ( (v_esc + sqrt(sum(v_lab**2.0))) / c_km)**2.0 / m_N return E_max_lim
def diffRecoilRate_SI(E_r, HaloIntegral, A, sigma_p, m_chi, rho_0=0.55): # E_r = Recoil energy in keVr # HaloIntegral = g(vmin) or fhat(vmin,q) for non-dir. or dir. experiment # A = Nucleus Mass Number # sigma_p = SI WIMP-proton cross section in cm^2 # m_chi = WIMP mass in GeV # rho_0 = Local DM density mu_p = 1.0e6 * m_chi * m_p / (1.0e6 * m_chi + m_p) # reduced mass FF = LabFuncs.FormFactorHelm(E_r, A)**2.0 # Form Factor^2 R0 = (c_cm * c_cm) * ((rho_0 * 1.0e6 * A * A * sigma_p) / (2 * m_chi * GeV_2_kg * mu_p * mu_p)) HaloIntegral = HaloIntegral / (1000.0 * 100.0) # convert to cm^-1 s # Compute rate = (Rate amplitude * HaloIntegral * form factor) dR = R0 * HaloIntegral * FF dR = dR * 3600 * 24 * 365 * 1000.0 # convert to units of 1/(keVr ton year) return dR
def VelocityDist_Triaxial(v,day=67.0,sig=Params.SHMpp.SausageDispersionTensor,\ v_LSR=Params.SHMpp.RotationSpeed,\ v_esc=Params.SHMpp.EscapeSpeed,\ v_shift=array([0.0,0.0,0.0]),GravFocus=False,\ GalFrame=False,\ EscapeSpeed=True,SmoothCutoff=False): ## Triaxial velocity distribution # v = velocities (in galactic cylindrical coordinates) # v_LSR = Local standard of rest # sig3 = 3d dispersion (array) # v_esc = escape speed # v_shift = any shift to v_lab needed (usually the stream velocity) # GravFocus = whether to calculate gravfocus or not v_lab = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR)-v_shift # Dispersions sigr = sig[0] sigphi = sig[1] sigz = sig[2] beta = 1.0-(sigphi**2.0+sigz**2.0)/(2*sigr**2.0) # Normalisation if beta>0.0: N_esc = Nesc_Triaxial(sigr,sigphi,beta,v_esc) elif beta==0.0: N_esc = Nesc_Isotropic(sigr,v_esc) else: N_esc = 1.0 N = 1.0/(N_esc*(2*pi)**(1.5)*sigr*sigphi*sigz) vr = v[:,0] # radial comp. vphi = v[:,1] # azimuthal comp. vz = v[:,2] # vertical comp. V = sqrt((vr+v_lab[0])**2.0+(vphi+v_lab[1])**2.0+(vz+v_lab[2])**2.0) # Speed # Now compute value of distribution fv3 = N*exp(-((vr+v_lab[0])**2.0/(2*sigr**2.0))\ -((vz+v_lab[2])**2.0/(2*sigz**2.0))\ -((vphi+v_lab[1])**2.0/(2*sigphi**2.0)))*(V<v_esc) return fv3
def gvmin_Isotropic(v_min,day,v_LSR=233.0,sig=164.75,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0]),GravFocus=False,v_exponent=-1.0): # MeanInverse Speed g(vmin) for an isotropic gaussian distribution # v_min = minimum wimp speed # day = day of the year, where Jan 1 = 0 # v_exponent = the exponent to raise v_min to in the integral (-1 gives g(vmin)) if (GravFocus) or (v_exponent!=-1.0): # If gravitational focusing is turned on then the integral needs to be # done numerically. I use flipud and then cumtrapz to do the integral # backwards over the range v_min_fine, which is then interpolated to # the input v_min v_min_fine = linspace(0.0001,800.0,300) fv = flipud((v_min_fine**v_exponent)*\ SpeedDist_Isotropic(v_min_fine,day,v_LSR=v_LSR,sig=sig,\ v_esc=v_esc,v_shift=v_shift,GravFocus=GravFocus)) gvmin_fine = zeros(shape=size(v_min_fine)) gvmin_fine[0:-1] = flipud(cumtrapz(fv,v_min_fine)) gvmin_fine[-1] = 0.0 gvmin = interp(v_min,v_min_fine,gvmin_fine) # interp to input v_min else: # If Grav focus being ignored and exponent=-1, can use analytic result v_lab = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR)-v_shift N_esc = Nesc_Isotropic(sig,v_esc) v_e = sqrt(sum(v_lab**2.0)) v0 = sig*sqrt(2.0) x = v_min/v0 z = v_esc/v0 y = v_e/v0 gvmin = zeros(shape=shape(v_min)) g1 = (1.0/(v0*y)) g2 = (1.0/(2.0*N_esc*v0*y))*(erf(x+y)-erf(x-y)-(4.0/sqrt(pi))*y*exp(-z**2)) g3 = (1.0/(2.0*N_esc*v0*y))*(erf(z)-erf(x-y)-(2.0/sqrt(pi))*(y+z-x)*exp(-z**2)) gvmin[(x<abs(y-z))&(z<y)] = g1 gvmin[(x<abs(y-z))&(z>y)] = g2[(x<abs(y-z))&(z>y)] gvmin[(abs(y-z)<x)&(x<(y+z))] = g3[(abs(y-z)<x)&(x<(y+z))] gvmin[(y+z)<x] = 0.0 return gvmin
def R_wimp(E_th,E_max,m_chi,sigma_p=1.0e-45,\ Nuc=Params.Ar40,Loc=Params.GranSasso,\ HaloModel=Params.SHM,eff_on=False,eres_on=False): nfine = 1000 Efine = logspace(-3.0, log10(200.0), nfine) DM = Params.WIMP(m_chi, sigma_p) # Calculate rate at day=67 to get ~average dR = dRdE_wimp(Efine, array([(Jan1 + 67.0)]), DM, HaloModel, Nuc, Loc) # Correct for efficiency if eff_on: dR *= LabFuncs.efficiency(Nuc, Efine) # Smear by energy resolution # if eres_on: # dR = SmearE(Efine,dR,energyresolution(Nuc,Efine)) # Window mask = (Efine < E_max) & (Efine > E_th) R = trapz(dR[mask], Efine[mask]) return R
def R_Indiv(s, E_th, E_max, Nuc=Params.Ar40, eff_on=False, eres_on=False): nfine = 1000 Efine = logspace(-3.0, log10(200.0), nfine) # Load nu flux data = loadtxt(nufile_dir + nuname[s] + nufile_root, delimiter=',') E_nu = data[:, 0] Flux = NuFlux[s] * data[:, 1] sol = False dR = dRdE_nu(Efine, Jan1 * ones(shape=nfine), sol, E_nu, Flux, Nuc=Nuc) # Correct for efficiency if eff_on: dR *= LabFuncs.efficiency(Nuc, Efine) # Smear by energy resolution # if eres_on: # dR = SmearE(Efine,dR,energyresolution(Nuc,Efine)) # Window mask = (Efine < E_max) & (Efine > E_th) R = trapz(dR[mask], Efine[mask]) return R
def GetLimits(m_vals, sigma_vals, HaloModel, Expt, Verbose=True): # Load neutrino backgrounds Background = NeutrinoFuncs.GetNuFluxes(Expt.EnergyThreshold, Expt.Nucleus) n_bg = Background.NumberOfNeutrinos R_bg = Background.Normalisations R_bg_err = Background.Uncertainties RD_nu = zeros(shape=(Expt.TotalNumberOfBins, n_bg)) for i in range(0, n_bg): RD_nu[:, i] = LabFuncs.BinEvents(Expt, NeutrinoFuncs.NuRate, Background, i) RD_nu[:, i] *= (1.0 / R_bg[i]) Background.RecoilDistribution(RD_nu) # Fix parameters for scan nm = size(m_vals) ns = size(sigma_vals) DL = zeros(shape=nm) X_in1 = zeros(shape=(n_bg + 1)) N_bg = zeros(shape=Expt.TotalNumberOfBins) for i in range(0, n_bg): N_bg = N_bg + R_bg[i] * Background.RD[:, i] # MASS SCAN: for im in range(0, nm): Signal = Params.WIMP(m_vals[im], 1.0e-45) RD_wimp = LabFuncs.BinEvents(Expt, WIMPFuncs.WIMPRate, Signal, HaloModel) Signal.RecoilDistribution(RD_wimp / 1.0e-45) # CROSS SECTION SCAN for j in range(0, ns): sigma_p = sigma_vals[j] N_signal = Signal.RD * sigma_p D_prev = 0.0 s_prev = sigma_p if sum(N_signal) > 0.5: # Generally need >0.5 events to see DM # ------ Asimov dat -----------# N_obs = N_signal + N_bg #------ Signal + Background ------# X_in1 = append(log10(sigma_p), R_bg) L1 = llhood1(X_in1, N_obs, Signal, Background) #------ Background only ------# X_in0 = R_bg step = R_bg_err res = minimize(llhood0, X_in0, args=(N_obs,Signal,Background)\ ,options={'xtol': R_bg_err, 'eps': 2*step}) L0 = res.fun #L0 = llhood0(X_in0,N_obs,Signal,Background) # Test statistic D01 = -2.0 * (L1 - L0) #print(j,sigma_p,D01,sum(N_signal),L1,L0) if D01 > 9.0: # Median 3sigma detection -> D = 9 # Do interpolation to find discovery limit cross section DL[im] = 10.0**(interp(9.0,array([D_prev,D01]),\ array([log10(s_prev),log10(sigma_p)]))) break s_prev = sigma_p # Reset for interpolation D_prev = D01 #Params.printProgressBar(im, nm) if Verbose: print("m_chi = ",m_vals[im],"| sigma_p = ",DL[im],\ "| # Signal = ",sum(N_signal),"| # Background = ",sum(N_bg)) return DL
def SpeedDist_Triaxial(v,day,sig3,v_LSR=233.0,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0]),GravFocus=False,\ GalFrame=False,\ EscapeSpeed=True,SmoothCutoff=False): ## Triaxial speed distribution # v = velocities (in galactic cylindrical coordinates) # v_LSR = Local standard of rest # sig3 = 3d dispersion (array) # v_esc = escape speed # v_shift = any shift to v_lab needed (usually the stream velocity) # GravFocus = whether to calculate gravfocus or not # GalFrame = whether to compute in Galactic Frame or not # EscapeSpeed = whether to have a finite escape speed or not # SmoothCutoff = whether to have a sharp or smooth escape speed cutoff # Dispersions sigr = sig3[0] sigphi = sig3[1] sigz = sig3[2] # Normalisation beta = 1.0-(sigphi**2.0+sigz**2.0)/(2*sigr**2.0) if beta>0.0: N_esc = Nesc_Triaxial(sigr,sigphi,beta,v_esc) elif beta==0.0: N_esc = Nesc_Isotropic(sigr,v_esc) else: N_esc = 1.0 if not EscapeSpeed: N_esc = 1.0 v_esc = 1000.0 N = 1.0/(N_esc*(2*pi)**(1.5)*sigr*sigphi*sigz) n = size(v) fv1 = zeros(shape=n) if GravFocus==False: if GalFrame: v_off = -v_shift # Shift back by -v_shift to undo shift v_max = v_esc else: v_e = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR) v_max = v_esc+sqrt(sum(v_e**2.0)) v_off = v_e-v_shift # Need a correction Fcorr if a smooth escape speed cutoff is needed if SmoothCutoff: vr = (v_max)*sqrt(1-C**2.0)*cos(P)+v_off[0] vphi = (v_max)*sqrt(1-C**2.0)*sin(P)+v_off[1] vz = (v_max)*C+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) Fcorr = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0))) else: Fcorr = 0.0 # Loop over speeds each step doing an angular integral for i in range(0,n): v1 = v[i] vr = v1*sqrt(1-C**2.0)*cos(P)+v_off[0] vphi = v1*sqrt(1-C**2.0)*sin(P)+v_off[1] vz = v1*C+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<v_esc) F = F-Fcorr # take off smooth cutoff correction fv1[i] = (v1**2.0)*dth*dph*sum(sum(F)) # sum over angles fv1[v>v_max] = 0.0 fv1 /= trapz(fv1,v) # renormalise for security else: ##### Gravitation focusing calculation ##### v_off = LabFuncs.v_pec+array([0.0,v_LSR,0.0])-v_shift vv_e = sqrt(sum(v_off**2.0)) v_max = v_esc+vv_e if SmoothCutoff: vr = (v_max)*sqrt(1-C**2.0)*cos(P) vphi = (v_max)*sqrt(1-C**2.0)*sin(P) vz = (v_max)*C V = sqrt(vr**2.0+vphi**2.0+vz**2.0) Fcorr = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0))) else: Fcorr = 0.0 # Loop over speeds each step doing an angular integral for i in range(0,n): v1 = v[i] # Transform velocities to v_infinity (needed to implement Grav focus) vr,vphi,vz = LabFuncs.v_infinity(v1,C,P,day) vr += v_off[0] vphi += v_off[1] vz += v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<(v_esc)) F = F-Fcorr fv1[i] = (v1**2.0)*dth*dph*sum(sum(F)) #################### return fv1
def VelocityDist1D_Triaxial(v,day,sig3,v_LSR=233.0,v_esc=528.0,\ v_shift=array([0.0,0.0,0.0]),GalFrame=False,\ EscapeSpeed=True,SmoothCutoff=False): # Same as previous function but finds the 1-dimensional speed distributions # along each galactic cylindrical coordinate sigr = sig3[0] sigphi = sig3[1] sigz = sig3[2] beta = 1.0-(sigphi**2.0+sigz**2.0)/(2*sigr**2.0) N_esc = 1.0 if not EscapeSpeed: N_esc = 1.0 v_esc = 1000.0 N = 1.0/(N_esc*(2*pi)**(1.5)*sigr*sigphi*sigz) n = size(v) fvr = zeros(shape=n) fvphi = zeros(shape=n) fvz = zeros(shape=n) if GalFrame: v_off = -v_shift v_max = v_esc else: v_e = LabFuncs.LabVelocitySimple(day,v_LSR=v_LSR) v_max = v_esc+sqrt(sum(v_e**2.0)) v_off = v_e-v_shift # discretisation of speeds in each dimension nfine = 51 vfine =linspace(-v_max,v_max,nfine) V1,V2 = meshgrid(vfine,vfine) dv = vfine[1]-vfine[0] if SmoothCutoff: vr = (v_max)*sqrt(1-C**2.0)*cos(P)+v_off[0] vphi = (v_max)*sqrt(1-C**2.0)*sin(P)+v_off[1] vz = (v_max)*C+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) Fcorr = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0))) else: Fcorr = 0.0 # Loop over speeds for i in range(0,n): # For each component create a matrix of velocities (V1,V2) # in the other two components and sum over those. # R-component vr = v[i]+v_off[0] vphi = V1+v_off[1] vz = V2+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<v_esc)-Fcorr fvr[i] = dv*dv*sum(sum(F)) # Phi-component vr = V1+v_off[0] vphi = v[i]+v_off[1] vz = V2+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<v_esc)-Fcorr fvphi[i] = dv*dv*sum(sum(F)) # Z-component vr = V1+v_off[0] vphi = V2+v_off[1] vz = v[i]+v_off[2] V = sqrt(vr**2.0+vphi**2.0+vz**2.0) F = N*exp(-(vr**2.0/(2*sigr**2.0))\ -(vz**2.0/(2*sigz**2.0))\ -(vphi**2.0/(2*sigphi**2.0)))*(V<v_esc)-Fcorr fvz[i] = dv*dv*sum(sum(F)) # Implement cutoff fvr[v>v_max] = 0.0 fvphi[v>v_max] = 0.0 fvz[v>v_max] = 0.0 # normalise each one fvr /= trapz(fvr,v) fvphi /= trapz(fvphi,v) fvz /= trapz(fvz,v) # Stack together for output fv3 = vstack((fvr.T,fvphi.T,fvz.T)) return fv3
def dRdEdO_solarnu(E,t,E_nu,Flux,Nuc,Loc): # Directional CEnuNS for Solar N = Nuc.NumberOfNeutrons Z = Nuc.NumberOfProtons Q_W = N-(1-4.0*sinTheta_Wsq)*Z # weak nuclear hypercharge m_N_GeV = 0.93141941*(N+Z) # nucleus mass in GeV m_N_keV = m_N_GeV*1.0e6 # nucleus mass in keV E_nu_keV = E_nu*1e3 E_r = sqrt(E[:,0]**2 + E[:,1]**2 + E[:,2]**2) # Recoil energy x = zeros(shape=shape(E)) x_sun = zeros(shape=shape(E)) x[:,0] = E[:,0]/E_r # Recoil direction x[:,1] = E[:,1]/E_r x[:,2] = E[:,2]/E_r ne =size(E_r) dRdEdO = zeros(shape=ne) for i in range(0,ne): x_sun[i,:] = LabFuncs.SolarDirection(t[i],Loc) cos_th_sun = -(x_sun[:,0]*x[:,0]+x_sun[:,1]*x[:,1]+x_sun[:,2]*x[:,2]) FF = LabFuncs.FormFactorHelm(E_r,N+Z)**2.0 # CHROMATIC NEUTRINOS if Flux[1]>0.0: E_max = 2*m_N_keV*E_nu_keV[-1]**2.0/(m_N_keV+E_nu_keV[-1])**2 i_range = range(0,ne)*(E_r<=E_max) i_sel = i_range[i_range!=0] for i in i_sel: costh = cos_th_sun[i] E_nu_min = sqrt(m_N_keV*E_r[i]/2.0) if costh>(E_nu_min/m_N_keV): Eps = 1.0/(costh/E_nu_min - 1.0/m_N_keV) diff_sigma = (G_F_GeV**2/(4*pi))*Q_W**2*m_N_GeV*\ (1-(m_N_keV*E_r[i])/(2*Eps**2))*(0.197e-13)**2.0\ *1e-6*1000/(N+1.0*Z)*(N_A) Eps = Eps*(Eps>E_nu_min) Eps = Eps*(Eps<E_nu_keV[-1]) F_value = interp(Eps,E_nu_keV,Flux) dRdEdO[i] = diff_sigma*F_value*Eps**2.0/(1000*E_nu_min)*FF[i] # /kg/keV # MONOCHROMATIC NEUTRINOS else: E_max = 2*m_N_keV*E_nu_keV[0]**2.0/(m_N_keV+E_nu_keV[0])**2 i_range = range(0,ne)*(E_r<=E_max) i_sel = i_range[i_range!=0] for i in i_sel: costh = cos_th_sun[i] E_nu_min = sqrt(m_N_keV*E_r[i]/2.0) costh_r = ((E_nu_keV[0]+m_N_keV)/E_nu_keV[0])*sqrt(E_r[i]/(2*m_N_keV)) # just need to accept angles close enough to costh_r to be accurate # around 0.01 is enough to be disguised by most angular resolutions if abs((costh)-(costh_r))<0.01: Eps = E_nu_keV[0] diff_sigma = (G_F_GeV**2/(4*pi))*Q_W**2*m_N_GeV*\ (1-(m_N_keV*E_r[i])/(2*Eps**2))*(0.197e-13)**2.0\ *1e-6*1000/(N+1.0*Z)*(N_A)*FF[i] dRdEdO[i] = diff_sigma*(Flux[0]/1000.0)*E_nu_keV[0] # /kg/keV fMod = LabFuncs.EarthSunDistanceMod(t) dRdEdO = fMod*dRdEdO*3600*24*365*1000/(2*pi) # /ton/year return dRdEdO
def GenerateAtmNuDirections(ngen, E_fine, Phi_fine, E_high, Phi_Ang, cosZ, phi_Az, Nuc): ngen_large = 2 * ngen ngen_red = 0 # Nucleus mass A = Nuc.MassNumber m_N_keV = A * 0.9315 * 1e6 # Flux binning nc = size(cosZ) np = size(phi_Az) [C, P] = meshgrid(cosZ, phi_Az) C = reshape(C, nc * np) P = reshape(P, nc * np) # Neutrino energy distribution fdist = (E_fine**2.0) * Phi_fine fdist = fdist / sum(fdist) # Get energies: E_gen_full = array([]) E_r_gen_full = array([]) while ngen_red < ngen: # Generate neutrino energies E_gen = random.choice(E_fine, p=fdist, size=ngen_large) # Generate recoil energies E_r_gen = (2 * m_N_keV * (E_gen * 1000)**2.0 / (m_N_keV + 1000 * E_gen)**2.0) * ( 1 - sqrt(random.uniform(size=ngen_large))) # Form Factor correction mask = (random.uniform(size=ngen_large) < LabFuncs.FormFactorHelm( E_r_gen, A)**2.0) E_gen_full = append(E_gen_full, E_gen[mask]) E_r_gen_full = append(E_r_gen_full, E_r_gen[mask]) ngen_red = shape(E_gen_full)[0] print('Filled ', 100 * ngen_red / (1.0 * ngen), '% of', ngen, 'samples') E_gen = E_gen_full[0:ngen] E_r_gen = E_r_gen_full[0:ngen] # Get angles: # Digitize to find which energy bin to use E_bin_gen = digitize(log10(E_gen), log10(E_high)) nhigh = size(E_high) phi_nu_gen = zeros(shape=ngen) costh_nu_gen = zeros(shape=ngen) for i in range(0, nhigh): # Select energy bin mask = E_bin_gen == i ngen_i = count_nonzero(mask) # Generate indices corresponding to 2D angular distribution fdist_CP = Phi_Ang[:, :, i] fdist_CP = reshape(fdist_CP, nc * np) fdist_CP = fdist_CP / sum(fdist_CP) igen = random.choice(arange(0, nc * np), p=fdist_CP, size=ngen_i) # Select phi and costh from generated index phi_nu_gen[mask] = P[igen] * pi / 180.0 costh_nu_gen[mask] = C[igen] dphi = (pi / 180) * (phi_Az[1] - phi_Az[0]) dcosth = (cosZ[1] - cosZ[0]) phi_nu_gen += (dphi / 2.0) * (2 * random.uniform(size=ngen) - 1) costh_nu_gen += (dcosth / 2.0) * (2 * random.uniform(size=ngen) - 1) return E_gen, phi_nu_gen, costh_nu_gen, E_r_gen