Esempio n. 1
0
 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
Esempio n. 2
0
 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
Esempio n. 3
0
 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
Esempio n. 4
0
 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
Esempio n. 5
0
 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
Esempio n. 6
0
 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
Esempio n. 7
0
 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
Esempio n. 8
0
 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))
Esempio n. 9
0
 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