def dscM(l, en, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density, and update the state-transition matrix modVAC to the current time/position. """ global lCache, aMSW, modVAC # if l did not change, the update is unnecessary if l == lCache: return # modVAC is the time-dependent state-transition matrix that brings a # state vector to the interaction basis, i.e., to the basis where # the vacuum oscillations are flat if isAnti: modVAC = dot(svdVAC0a * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2a) else: modVAC = dot(svdVAC0n * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2n) # <==> modVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*(L-l)))), svdVAC2) # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= rICore: aMSW = aMSWWoRhoICore * profInt(r) elif r <= rOCore: aMSW = aMSWWoRhoOCore * profInt(r) else: aMSW = aMSWWoRho * profInt(r) lCache = l
def dscM(l, en, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density, and update the state-transition matrix modVAC to the current time/position. """ global lCache, aMSW, modVAC # if l did not change, the update is unnecessary if l == lCache: return # modVAC is the time-dependent state-transition matrix that brings a state # vector to the interaction basis, i.e., to the basis where the vacuum # oscillations are flat; see calcProb docstring for magic-number explanation if isAnti: modVAC = dot(svdVAC0a * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2a) else: modVAC = dot(svdVAC0n * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2n) # <==> modVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*(L-l)))), svdVAC2) # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= rICore: aMSW = aMSWWoRhoICore * profInt(r) elif r <= rOCore: aMSW = aMSWWoRhoOCore * profInt(r) else: aMSW = aMSWWoRho * profInt(r) lCache = l
def __get_normal_order(self, key, op): l1, l2 = key # assert(l1 != l2) if l1 == l2: print('wrong position for two body gate.') if isinstance(op, tuple): # assert(len(op)==2 and op[0].rank==3 and op[1].rank==3) # assert((l1[0] == l2[0] and l1[1]+1==l2[1]) or (l1[0]+1==l2[0] and l1[1]==l2[1])) if not (len(op) == 2 and op[0].rank == 3 and op[1].rank == 3): raise ValueError('wrong input op for two body gate.') if not ((l1[0] == l2[0] and l1[1] + 1 == l2[1]) or (l1[0] + 1 == l2[0] and l1[1] == l2[1])): raise ValueError('wrong position for two body gate.') else: op = astensor(op) # assert(len(l1)==2 and len(l2)==2) if not (len(l1) == 2 and len(l2) == 2): raise ValueError('wrong position for two body gate.') if op.rank == 2: # assert(op.shape==(4,4) or op.shape==(16,16)) if op.shape != (4, 4): raise ValueError('wrong op shape for two body gate.') s = int(ssqrt(op.shape[0])) op = op.reshape((s, s, s, s)) else: # assert(op.rank==4 and (op.shape==(2,2,2,2) or op.shape==(4,4,4,4))) if op.shape != (2, 2, 2, 2): raise ValueError('wrong op shape for two body gate.') if ((l1[0] == l2[0] and l1[1] == l2[1] + 1) or (l1[0] == l2[0] + 1 and l1[1] == l2[1])): op = op.transpose((1, 0, 3, 2)) key = (l2, l1) op = split_bondmpo(op) return key, op
def dscM(l, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density. """ global lCache, aMSW # if l did not change, the update is unnecessary if l == lCache: return # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= self.earthModel.rICore: aMSW = aMSWWoRhoICore * self.earthModel.profInt(r) elif r <= self.earthModel.rOCore: aMSW = aMSWWoRhoOCore * self.earthModel.profInt(r) else: aMSW = aMSWWoRho * self.earthModel.profInt(r) lCache = l
def calcProb(inTuple): """ Calculate the oscillation probabilities of an individual nu. The constant -2.533866j that appears throughout this function is -j*1.266933, where j is the imaginary unit and the other factor is GeV*fm/(4*hbar*c), which is the factor required to transition from natural units to SI units. It is hard-coded as it is not a free parameter and will never change. """ # python 3 does not support tuple parameter unpacking anymore mcType, mcEn, mcZen = inTuple def dscM(l, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density. """ global lCache, aMSW # if l did not change, the update is unnecessary if l == lCache: return # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= self.earthModel.rICore: aMSW = aMSWWoRhoICore * self.earthModel.profInt(r) elif r <= self.earthModel.rOCore: aMSW = aMSWWoRhoOCore * self.earthModel.profInt(r) else: aMSW = aMSWWoRho * self.earthModel.profInt(r) lCache = l def f(l, psi, en, zen): dscM(l, zen) # see calcProb docstring for magic-number explanation if isAnti: return -2.533866j/en * dot((VACa + aMSW), psi) else: return -2.533866j/en * dot((VACn + aMSW), psi) def jac(l, psi, en, zen): dscM(l, zen) if isAnti: return -2.533866j/en * (VACa + aMSW) else: return -2.533866j/en * (VACn + aMSW) try: mcType = self.mcTypeDict[mcType] except KeyError: raise KeyError("The mcType %d is not known to nuCraft!" % mcType) isAnti = mcType[0] == -1 # inefficient performance-wise, but nicer code, and vacuum is fast enough anyway if vacuum: aMSWWoRho = diag(zeros_like(self.earthModel.A)) aMSWWoRhoOCore = aMSWWoRho aMSWWoRhoICore = aMSWWoRho else: aMSWWoRho = diag(mcType[0] * self.earthModel.A * mcEn) aMSWWoRhoOCore = diag(mcType[0] * self.earthModel.AOCore * mcEn) aMSWWoRhoICore = diag(mcType[0] * self.earthModel.AICore * mcEn) L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) dscM(L, mcZen) solver = integrate.ode(f, jac).set_integrator('zvode', method='adams', order=5, with_jacobian=True, nsteps=12000000, atol=numPrec*2e-2, rtol=numPrec*2e-2) solver.set_initial_value(mcType[1], L).set_f_params(mcEn, mcZen).set_jac_params(mcEn, mcZen) solver.integrate(0.) if not solver.successful(): raise ArithmeticError("ODE solver was not successful, check for warnings about 'excess work done'!") prob = square(absolute(solver.y)) if abs(1-sum(prob)) > numPrec: warnings.warn("The computed unitarity does not meet the specified precision: %.2e > %.2e" % (abs(1-sum(prob)), numPrec)) return prob
def calcProb(inTuple): """ Calculate the oscillation probabilities of an individual nu. The constant -2.533866j that appears throughout this function is -2*j*1.266933, where j is the imaginary unit and the other factor is GeV*fm/(4*hbar*c), which is the factor required to transition from natural units to SI units. It is hard-coded as it is not a free parameter and will never change. """ # python 3 does not support tuple parameter unpacking anymore mcType, mcEn, mcZen = inTuple def dscM(l, en, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density, and update the state-transition matrix modVAC to the current time/position. """ global lCache, aMSW, modVAC # if l did not change, the update is unnecessary if l == lCache: return # modVAC is the time-dependent state-transition matrix that brings a state # vector to the interaction basis, i.e., to the basis where the vacuum # oscillations are flat; see calcProb docstring for magic-number explanation if isAnti: modVAC = dot(svdVAC0a * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2a) else: modVAC = dot(svdVAC0n * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2n) # <==> modVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*(L-l)))), svdVAC2) # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= rICore: aMSW = aMSWWoRhoICore * profInt(r) elif r <= rOCore: aMSW = aMSWWoRhoOCore * profInt(r) else: aMSW = aMSWWoRho * profInt(r) lCache = l def f(l, psi, en, zen): dscM(l, en, zen) return -2.533866j/en * dot(modVAC, aMSW*dot(psi, conj(modVAC))) # <==> return -2.533866j/en * dot(modVAC, dot(diag(aMSW), dot(conj(modVAC).T, psi))) def jac(l, psi, en, zen): dscM(l, en, zen) return -2.533866j/en * dot(modVAC*aMSW, conj(modVAC).T) # <==> return -2.533866j/en * dot(dot(modVAC, diag(aMSW)), conj(modVAC).T) try: mcType = self.mcTypeDict[mcType] except KeyError: raise KeyError("The mcType %d is not known to nuCraft!" % mcType) isAnti = mcType[0] == -1 # inefficient performance-wise, but nicer code, and vacuum is fast enough anyway if vacuum: aMSWWoRho = zeros_like(self.earthModel.A) aMSWWoRhoOCore = aMSWWoRho aMSWWoRhoICore = aMSWWoRho else: aMSWWoRho = mcType[0] * self.earthModel.A * mcEn aMSWWoRhoOCore = mcType[0] * self.earthModel.AOCore * mcEn aMSWWoRhoICore = mcType[0] * self.earthModel.AICore * mcEn # depending on the mode, get a list of interaction altitude tuples, see method doc string; # the first number of the tuples is the weight, the second the distance of the interaction # point to the center of the Earth; the weights have to add up to 1. if atmMode == 3: # first get the tuples and propagate only the lowest-altitude neutrino: rAtmTuples = self.InteractionAlt(mcType, mcEn, mcZen, 2) rAtm = rAtmTuples[0][1] L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) dscM(L, mcEn, mcZen) solver = integrate.ode(f, jac).set_integrator('zvode', method='adams', order=5, with_jacobian=True, nsteps=1200000, atol=numPrec*2e-3, rtol=numPrec*2e-3) solver.set_initial_value(dot(modVAC, mcType[1]), L).set_f_params(mcEn, mcZen).set_jac_params(mcEn, mcZen) solver.integrate(0.) if isAnti: endVAC = dot(svdVAC0a * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2a) else: endVAC = dot(svdVAC0n * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2n) # <==> endVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*L))), svdVAC2) results = [rAtmTuples[0][0] * square(absolute( dot(conj(endVAC).T, solver.y) ))] # now for all the other neutrinos, add the missing lengths as vacuum oscillations # at the end of the track; keep in mind that atmosphere is always handled as vacuum for rAtmWeight, rAtm in rAtmTuples[1:]: L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) if isAnti: endVAC = dot(svdVAC0a * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2a) else: endVAC = dot(svdVAC0n * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2n) results.append( rAtmWeight * square(absolute( dot(conj(endVAC).T, solver.y) )) ) else: # in this case, just stupidly propagate every neutrino in the list... results = [] for rAtmWeight, rAtm in self.InteractionAlt(mcType, mcEn, mcZen, atmMode): L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) dscM(L, mcEn, mcZen) solver = integrate.ode(f, jac).set_integrator('zvode', method='adams', order=5, with_jacobian=True, nsteps=1200000, atol=numPrec*2e-3, rtol=numPrec*2e-3) solver.set_initial_value(dot(modVAC, mcType[1]), L).set_f_params(mcEn, mcZen).set_jac_params(mcEn, mcZen) solver.integrate(0.) if isAnti: endVAC = dot(svdVAC0a * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2a) else: endVAC = dot(svdVAC0n * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2n) # <==> endVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*L))), svdVAC2) results.append( rAtmWeight * square(absolute( dot(conj(endVAC).T, solver.y) )) ) if not solver.successful(): raise ArithmeticError("ODE solver was not successful, check for warnings about 'excess work done'!") prob = sum(results, 0) if abs(1-sum(prob)) > numPrec: warnings.warn("The computed unitarity does not meet the specified precision: %.2e > %.2e" % (abs(1-sum(prob)), numPrec)) return prob
def calcProb(inTuple): """ Calculate the oscillation probabilities of an individual nu. """ # python 3 does not support tuple parameter unpacking anymore mcType, mcEn, mcZen = inTuple def dscM(l, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density. """ global lCache, aMSW # if l did not change, the update is unnecessary if l == lCache: return # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= self.earthModel.rICore: aMSW = aMSWWoRhoICore * self.earthModel.profInt(r) elif r <= self.earthModel.rOCore: aMSW = aMSWWoRhoOCore * self.earthModel.profInt(r) else: aMSW = aMSWWoRho * self.earthModel.profInt(r) lCache = l def f(l, psi, en, zen): dscM(l, zen) if isAnti: return -2.533866j/en * dot((VACa + aMSW), psi) else: return -2.533866j/en * dot((VACn + aMSW), psi) def jac(l, psi, en, zen): dscM(l, zen) if isAnti: return -2.533866j/en * (VACa + aMSW) else: return -2.533866j/en * (VACn + aMSW) try: mcType = self.mcTypeDict[mcType] except KeyError: raise KeyError("The mcType %d is not known to nuCraft!" % mcType) isAnti = mcType[0] == -1 # inefficient performance-wise, but nicer code, and vacuum is fast enough anyway if vacuum: aMSWWoRho = diag(zeros_like(self.earthModel.A)) aMSWWoRhoOCore = aMSWWoRho aMSWWoRhoICore = aMSWWoRho else: aMSWWoRho = diag(mcType[0] * self.earthModel.A * mcEn) aMSWWoRhoOCore = diag(mcType[0] * self.earthModel.AOCore * mcEn) aMSWWoRhoICore = diag(mcType[0] * self.earthModel.AICore * mcEn) L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) dscM(L, mcZen) solver = integrate.ode(f, jac).set_integrator('zvode', method='adams', order=4, with_jacobian=True, nsteps=1200000, min_step=0.0002, max_step=500., atol=.1e-6, rtol=.1e-6) solver.set_initial_value(mcType[1], L).set_f_params(mcEn, mcZen).set_jac_params(mcEn, mcZen) solver.integrate(0.) return square(absolute(solver.y))
def calcProb(inTuple): """ Calculate the oscillation probabilities of an individual nu. """ # python 3 does not support tuple parameter unpacking anymore mcType, mcEn, mcZen = inTuple def dscM(l, en, zen): """ Update the MSW-induced mass-squared matrix aMSW with the current density, and update the state-transition matrix modVAC to the current time/position. """ global lCache, aMSW, modVAC # if l did not change, the update is unnecessary if l == lCache: return # modVAC is the time-dependent state-transition matrix that brings a # state vector to the interaction basis, i.e., to the basis where # the vacuum oscillations are flat if isAnti: modVAC = dot(svdVAC0a * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2a) else: modVAC = dot(svdVAC0n * exp(-2.533866j/en*svdVAC1*(L-l)), svdVAC2n) # <==> modVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*(L-l)))), svdVAC2) # distance from the center of Earth r = ssqrt( l*l + rDet*rDet - 2*l*rDet*scos(pi - zen) ) if r <= rICore: aMSW = aMSWWoRhoICore * profInt(r) elif r <= rOCore: aMSW = aMSWWoRhoOCore * profInt(r) else: aMSW = aMSWWoRho * profInt(r) lCache = l def f(l, psi, en, zen): dscM(l, en, zen) return -2.533866j/en * dot(modVAC, aMSW*dot(psi, conj(modVAC))) # <==> return -2.533866j/en * dot(modVAC, dot(diag(aMSW), dot(conj(modVAC).T, psi))) def jac(l, psi, en, zen): dscM(l, en, zen) return -2.533866j/en * dot(modVAC*aMSW, conj(modVAC).T) # <==> return -2.533866j/en * dot(dot(modVAC, diag(aMSW)), conj(modVAC).T) try: mcType = self.mcTypeDict[mcType] except KeyError: raise KeyError("The mcType %d is not known to nuCraft!" % mcType) isAnti = mcType[0] == -1 # inefficient performance-wise, but nicer code, and vacuum is fast enough anyway if vacuum: aMSWWoRho = zeros_like(self.earthModel.A) aMSWWoRhoOCore = aMSWWoRho aMSWWoRhoICore = aMSWWoRho else: aMSWWoRho = mcType[0] * self.earthModel.A * mcEn aMSWWoRhoOCore = mcType[0] * self.earthModel.AOCore * mcEn aMSWWoRhoICore = mcType[0] * self.earthModel.AICore * mcEn # depending on the mode, get a list of interaction altitude tuples, see method doc string; # the first number of the tuples is the weight, the second the distance of the interaction # point to the center of the Earth; the weights have to add up to 1. if atmMode == 3: # first get the tuples and propagate only the lowest-altitude neutrino: rAtmTuples = self.InteractionAlt(mcType, mcEn, mcZen, 2) rAtm = rAtmTuples[0][1] L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) dscM(L, mcEn, mcZen) solver = integrate.ode(f, jac).set_integrator('zvode', method='adams', order=4, with_jacobian=True, nsteps=120000, min_step=0.0002, max_step=500., atol=numPrec*2e-3, rtol=numPrec*2e-3) solver.set_initial_value(dot(modVAC, mcType[1]), L).set_f_params(mcEn, mcZen).set_jac_params(mcEn, mcZen) solver.integrate(0.) if isAnti: endVAC = dot(svdVAC0a * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2a) else: endVAC = dot(svdVAC0n * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2n) # <==> endVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*L))), svdVAC2) results = [rAtmTuples[0][0] * square(absolute( dot(conj(endVAC).T, solver.y) ))] # now for all the other neutrinos, add the missing lengths as vacuum oscillations # at the end of the track; keep in mind that atmosphere is always handled as vacuum for rAtmWeight, rAtm in rAtmTuples[1:]: L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) if isAnti: endVAC = dot(svdVAC0a * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2a) else: endVAC = dot(svdVAC0n * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2n) results.append( rAtmWeight * square(absolute( dot(conj(endVAC).T, solver.y) )) ) else: # in this case, just stupidly propagate every neutrino in the list... results = [] for rAtmWeight, rAtm in self.InteractionAlt(mcType, mcEn, mcZen, atmMode): L = ssqrt( rAtm*rAtm + rDet*rDet - 2*rAtm*rDet*scos( mcZen - arcsin(sin(pi-mcZen)/rAtm*rDet) ) ) dscM(L, mcEn, mcZen) solver = integrate.ode(f, jac).set_integrator('zvode', method='adams', order=4, with_jacobian=True, nsteps=120000, min_step=0.0002, max_step=500., atol=numPrec*2e-3, rtol=numPrec*2e-3) solver.set_initial_value(dot(modVAC, mcType[1]), L).set_f_params(mcEn, mcZen).set_jac_params(mcEn, mcZen) solver.integrate(0.) if isAnti: endVAC = dot(svdVAC0a * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2a) else: endVAC = dot(svdVAC0n * exp(-2.533866j/mcEn*svdVAC1*L), svdVAC2n) # <==> endVAC = dot(dot(svdVAC0, diag(exp(-2.533866j/mcEn*svdVAC1*L))), svdVAC2) results.append( rAtmWeight * square(absolute( dot(conj(endVAC).T, solver.y) )) ) prob = sum(results, 0) if abs(1-sum(prob)) > numPrec: warnings.warn("The computed unitarity does not meet the specified precision: %.2e > %.2e" % (abs(1-sum(prob)), numPrec)) return prob