Пример #1
0
 def _evaluate(self,*args,**kwargs):
     """
     NAME:
        __call__ (_evaluate)
     PURPOSE:
        evaluate the actions (jr,lz,jz)
     INPUT:
        Either:
           a) R,vR,vT,z,vz[,phi]:
              1) floats: phase-space value for single object (phi is optional) (each can be a Quantity)
              2) numpy.ndarray: [N] phase-space values for N objects (each can be a Quantity)
           b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well as the second argument
        cumul= if True, return the cumulative average actions (to look 
               at convergence)
     OUTPUT:
        (jr,lz,jz)
     HISTORY:
        2013-09-10 - Written - Bovy (IAS)
     """
     R,vR,vT,z,vz,phi= self._parse_args(False,False,*args)
     if self._c: #pragma: no cover
         pass
     else:
         #Use self._aAI to calculate the actions and angles in the isochrone potential
         acfs= self._aAI._actionsFreqsAngles(R.flatten(),
                                             vR.flatten(),
                                             vT.flatten(),
                                             z.flatten(),
                                             vz.flatten(),
                                             phi.flatten())
         jrI= nu.reshape(acfs[0],R.shape)[:,:-1]
         jzI= nu.reshape(acfs[2],R.shape)[:,:-1]
         anglerI= nu.reshape(acfs[6],R.shape)
         anglezI= nu.reshape(acfs[8],R.shape)
         if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full radial angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full vertical angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         danglerI= ((nu.roll(anglerI,-1,axis=1)-anglerI) % _TWOPI)[:,:-1]
         danglezI= ((nu.roll(anglezI,-1,axis=1)-anglezI) % _TWOPI)[:,:-1]
         if kwargs.get('cumul',False):
             sumFunc= nu.cumsum
         else:
             sumFunc= nu.sum
         jr= sumFunc(jrI*danglerI,axis=1)/sumFunc(danglerI,axis=1)
         jz= sumFunc(jzI*danglezI,axis=1)/sumFunc(danglezI,axis=1)
         if _isNonAxi(self._pot):
             lzI= nu.reshape(acfs[1],R.shape)[:,:-1]
             anglephiI= nu.reshape(acfs[7],R.shape)
             danglephiI= ((nu.roll(anglephiI,-1,axis=1)-anglephiI) % _TWOPI)[:,:-1]
             if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\
                           *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover
                 warnings.warn("Full azimuthal angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
             lz= sumFunc(lzI*danglephiI,axis=1)/sumFunc(danglephiI,axis=1)
         else:
             lz= R[:,0]*vT[:,0]
         return (jr,lz,jz)
Пример #2
0
 def _evaluate(self,*args,**kwargs):
     """
     NAME:
        __call__ (_evaluate)
     PURPOSE:
        evaluate the actions (jr,lz,jz)
     INPUT:
        Either:
           a) R,vR,vT,z,vz[,phi]:
              1) floats: phase-space value for single object (phi is optional) (each can be a Quantity)
              2) numpy.ndarray: [N] phase-space values for N objects (each can be a Quantity)
           b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well as the second argument
        cumul= if True, return the cumulative average actions (to look 
               at convergence)
     OUTPUT:
        (jr,lz,jz)
     HISTORY:
        2013-09-10 - Written - Bovy (IAS)
     """
     R,vR,vT,z,vz,phi= self._parse_args(False,False,*args)
     if self._c: #pragma: no cover
         pass
     else:
         #Use self._aAI to calculate the actions and angles in the isochrone potential
         acfs= self._aAI._actionsFreqsAngles(R.flatten(),
                                             vR.flatten(),
                                             vT.flatten(),
                                             z.flatten(),
                                             vz.flatten(),
                                             phi.flatten())
         jrI= nu.reshape(acfs[0],R.shape)[:,:-1]
         jzI= nu.reshape(acfs[2],R.shape)[:,:-1]
         anglerI= nu.reshape(acfs[6],R.shape)
         anglezI= nu.reshape(acfs[8],R.shape)
         if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full radial angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full vertical angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         danglerI= ((nu.roll(anglerI,-1,axis=1)-anglerI) % _TWOPI)[:,:-1]
         danglezI= ((nu.roll(anglezI,-1,axis=1)-anglezI) % _TWOPI)[:,:-1]
         if kwargs.get('cumul',False):
             sumFunc= nu.cumsum
         else:
             sumFunc= nu.sum
         jr= sumFunc(jrI*danglerI,axis=1)/sumFunc(danglerI,axis=1)
         jz= sumFunc(jzI*danglezI,axis=1)/sumFunc(danglezI,axis=1)
         if _isNonAxi(self._pot):
             lzI= nu.reshape(acfs[1],R.shape)[:,:-1]
             anglephiI= nu.reshape(acfs[7],R.shape)
             danglephiI= ((nu.roll(anglephiI,-1,axis=1)-anglephiI) % _TWOPI)[:,:-1]
             if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\
                           *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover
                 warnings.warn("Full azimuthal angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
             lz= sumFunc(lzI*danglephiI,axis=1)/sumFunc(danglephiI,axis=1)
         else:
             lz= R[:,0]*vT[:,0]
         return (jr,lz,jz)
Пример #3
0
    def __init__(self, *args, **kwargs):
        """
        NAME:

           __init__

        PURPOSE:

           initialize an actionAngleTorus object

        INPUT:

           pot= potential or list of potentials (3D)

           tol= default tolerance to use when fitting tori (|dJ|/J)

           dJ= default action difference when computing derivatives (Hessian or Jacobian)

        OUTPUT:

           instance

        HISTORY:

           2015-08-07 - Written - Bovy (UofT)

        """
        if not 'pot' in kwargs:  #pragma: no cover
            raise IOError("Must specify pot= for actionAngleTorus")
        self._pot = kwargs['pot']
        if _isNonAxi(self._pot):
            raise RuntimeError(
                "actionAngleTorus for non-axisymmetric potentials is not supported"
            )
        if self._pot == MWPotential:
            warnings.warn(
                "Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy",
                galpyWarning)
        if ext_loaded:
            self._c = _check_c(self._pot)
            if not self._c:
                raise RuntimeError(
                    'The given potential is not fully implemented in C; using the actionAngleTorus code is not supported in pure Python'
                )
        else:  # pragma: no cover
            raise RuntimeError(
                'actionAngleTorus instances cannot be used, because the actionAngleTorus_c extension failed to load'
            )
        self._tol = kwargs.get('tol', 0.001)
        self._dJ = kwargs.get('dJ', 0.001)
        return None
Пример #4
0
    def __init__(self,*args,**kwargs):
        """
        NAME:

           __init__

        PURPOSE:

           initialize an actionAngleTorus object

        INPUT:

           pot= potential or list of potentials (3D)

           tol= default tolerance to use when fitting tori (|dJ|/J)

           dJ= default action difference when computing derivatives (Hessian or Jacobian)

        OUTPUT:

           instance

        HISTORY:

           2015-08-07 - Written - Bovy (UofT)

        """
        if not 'pot' in kwargs: #pragma: no cover
            raise IOError("Must specify pot= for actionAngleTorus")
        self._pot= kwargs['pot']
        if _isNonAxi(self._pot):
            raise RuntimeError("actionAngleTorus for non-axisymmetric potentials is not supported")
        if self._pot == MWPotential:
            warnings.warn("Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy",
                          galpyWarning)
        if ext_loaded:
            self._c= _check_c(self._pot)
            if not self._c:
                raise RuntimeError('The given potential is not fully implemented in C; using the actionAngleTorus code is not supported in pure Python')
        else:# pragma: no cover
            raise RuntimeError('actionAngleTorus instances cannot be used, because the actionAngleTorus_c extension failed to load')
        self._tol= kwargs.get('tol',0.001)
        self._dJ= kwargs.get('dJ',0.001)
        return None
 def _actionsFreqsAngles(self,*args,**kwargs):
     """
     NAME:
        _actionsFreqsAngles
     PURPOSE:
        evaluate the actions, frequencies, and angles 
        (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     INPUT:
        Either:
           a) R,vR,vT,z,vz:
              1) floats: phase-space value for single object
              2) numpy.ndarray: [N] phase-space values for N objects 
              3) numpy.ndarray: [N,M] phase-space values for N objects at M
                 times
           b) Orbit instance or list thereof; can be integrated already
        maxn= (default: object-wide default) Use a grid in vec(n) up to this n (zero-based)
        ts= if set, the phase-space points correspond to these times (IF NOT SET, WE ASSUME THAT ts IS THAT THAT IS ASSOCIATED WITH THIS OBJECT)
        _firstFlip= (False) if True and Orbits are given, the backward part of the orbit is integrated first and stored in the Orbit object
     OUTPUT:
         (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     HISTORY:
        2013-09-10 - Written - Bovy (IAS)
     """
     from galpy.orbit import Orbit
     _firstFlip= kwargs.get('_firstFlip',False)
     #If the orbit was already integrated, set ts to the integration times
     if isinstance(args[0],Orbit) and hasattr(args[0]._orb,'orbit') \
             and not 'ts' in kwargs:
         kwargs['ts']= args[0]._orb.t
     elif (isinstance(args[0],list) and isinstance(args[0][0],Orbit)) \
             and hasattr(args[0][0]._orb,'orbit')  \
             and not 'ts' in kwargs:
         kwargs['ts']= args[0][0]._orb.t
     R,vR,vT,z,vz,phi= self._parse_args(True,_firstFlip,*args)
     if 'ts' in kwargs and not kwargs['ts'] is None:
         ts= kwargs['ts']
         if _APY_LOADED and isinstance(ts,units.Quantity):
             ts= ts.to(units.Gyr).value\
                 /time_in_Gyr(self._vo,self._ro)
     else:
         ts= nu.empty(R.shape[1])
         ts[self._ntintJ-1:]= self._tsJ
         ts[:self._ntintJ-1]= -self._tsJ[1:][::-1]
     maxn= kwargs.get('maxn',self._maxn)
     if self._c: #pragma: no cover
         pass
     else:
         #Use self._aAI to calculate the actions and angles in the isochrone potential
         if '_acfs' in kwargs: acfs= kwargs['_acfs']
         else:
             acfs= self._aAI._actionsFreqsAngles(R.flatten(),
                                                 vR.flatten(),
                                                 vT.flatten(),
                                                 z.flatten(),
                                                 vz.flatten(),
                                                 phi.flatten())
         jrI= nu.reshape(acfs[0],R.shape)[:,:-1]
         jzI= nu.reshape(acfs[2],R.shape)[:,:-1]
         anglerI= nu.reshape(acfs[6],R.shape)
         anglezI= nu.reshape(acfs[8],R.shape)
         if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full radial angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full vertical angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         danglerI= ((nu.roll(anglerI,-1,axis=1)-anglerI) % _TWOPI)[:,:-1]
         danglezI= ((nu.roll(anglezI,-1,axis=1)-anglezI) % _TWOPI)[:,:-1]
         jr= nu.sum(jrI*danglerI,axis=1)/nu.sum(danglerI,axis=1)
         jz= nu.sum(jzI*danglezI,axis=1)/nu.sum(danglezI,axis=1)
         if _isNonAxi(self._pot): #pragma: no cover
             lzI= nu.reshape(acfs[1],R.shape)[:,:-1]
             anglephiI= nu.reshape(acfs[7],R.shape)
             if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\
                           *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover
                 warnings.warn("Full azimuthal angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
             danglephiI= ((nu.roll(anglephiI,-1,axis=1)-anglephiI) % _TWOPI)[:,:-1]
             lz= nu.sum(lzI*danglephiI,axis=1)/nu.sum(danglephiI,axis=1)
         else:
             lz= R[:,len(ts)//2]*vT[:,len(ts)//2]
         #Now do an 'angle-fit'
         angleRT= dePeriod(nu.reshape(acfs[6],R.shape))
         acfs7= nu.reshape(acfs[7],R.shape)
         negFreqIndx= nu.median(acfs7-nu.roll(acfs7,1,axis=1),axis=1) < 0. #anglephi is decreasing
         anglephiT= nu.empty(acfs7.shape)
         anglephiT[negFreqIndx,:]= dePeriod(_TWOPI-acfs7[negFreqIndx,:])
         negFreqPhi= nu.zeros(R.shape[0],dtype='bool')
         negFreqPhi[negFreqIndx]= True
         anglephiT[True-negFreqIndx,:]= dePeriod(acfs7[True-negFreqIndx,:])
         angleZT= dePeriod(nu.reshape(acfs[8],R.shape))
         #Write the angle-fit as Y=AX, build A and Y
         nt= len(ts)
         no= R.shape[0]
         #remove 0,0,0 and half-plane
         if _isNonAxi(self._pot):
             nn= (2*maxn-1)**2*maxn-(maxn-1)*(2*maxn-1)-maxn
         else:
             nn= maxn*(2*maxn-1)-maxn 
         A= nu.zeros((no,nt,2+nn))
         A[:,:,0]= 1.
         A[:,:,1]= ts
         #sorting the phi and Z grids this way makes it easy to exclude the origin
         phig= list(nu.arange(-maxn+1,maxn,1))
         phig.sort(key = lambda x: abs(x))
         phig= nu.array(phig,dtype='int')
         if _isNonAxi(self._pot):
             grid= nu.meshgrid(nu.arange(maxn),phig,phig)
         else:
             grid= nu.meshgrid(nu.arange(maxn),phig)
         gridR= grid[0].T.flatten()[1:] #remove 0,0,0
         gridZ= grid[1].T.flatten()[1:]
         mask = nu.ones(len(gridR),dtype=bool)
         # excludes axis that is not in half-space
         if _isNonAxi(self._pot):
             gridphi= grid[2].T.flatten()[1:]
             mask= True\
                 -(gridR == 0)*((gridphi < 0)+((gridphi==0)*(gridZ < 0)))
         else:
             mask[:2*maxn-3:2]= False
         gridR= gridR[mask]
         gridZ= gridZ[mask]
         tangleR= nu.tile(angleRT.T,(nn,1,1)).T
         tgridR= nu.tile(gridR,(no,nt,1))
         tangleZ= nu.tile(angleZT.T,(nn,1,1)).T
         tgridZ= nu.tile(gridZ,(no,nt,1))
         if _isNonAxi(self._pot):
             gridphi= gridphi[mask]
             tgridphi= nu.tile(gridphi,(no,nt,1))
             tanglephi= nu.tile(anglephiT.T,(nn,1,1)).T
             sinnR= nu.sin(tgridR*tangleR+tgridphi*tanglephi+tgridZ*tangleZ)
         else:
             sinnR= nu.sin(tgridR*tangleR+tgridZ*tangleZ)
         A[:,:,2:]= sinnR
         #Matrix magic
         atainv= nu.empty((no,2+nn,2+nn))
         AT= nu.transpose(A,axes=(0,2,1))
         for ii in range(no):
             atainv[ii,:,:,]= linalg.inv(nu.dot(AT[ii,:,:],A[ii,:,:]))
         ATAR= nu.sum(AT*nu.transpose(nu.tile(angleRT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         ATAT= nu.sum(AT*nu.transpose(nu.tile(anglephiT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         ATAZ= nu.sum(AT*nu.transpose(nu.tile(angleZT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         angleR= nu.sum(atainv[:,0,:]*ATAR,axis=1)
         OmegaR= nu.sum(atainv[:,1,:]*ATAR,axis=1)
         anglephi= nu.sum(atainv[:,0,:]*ATAT,axis=1)
         Omegaphi= nu.sum(atainv[:,1,:]*ATAT,axis=1)
         angleZ= nu.sum(atainv[:,0,:]*ATAZ,axis=1)
         OmegaZ= nu.sum(atainv[:,1,:]*ATAZ,axis=1)
         Omegaphi[negFreqIndx]= -Omegaphi[negFreqIndx]
         anglephi[negFreqIndx]= _TWOPI-anglephi[negFreqIndx]
         if kwargs.get('_retacfs',False):
             return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ, #pragma: no cover
                     angleR % _TWOPI,
                     anglephi % _TWOPI,
                     angleZ % _TWOPI,acfs)
         else:
             return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ,
                     angleR % _TWOPI,
                     anglephi % _TWOPI,
                     angleZ % _TWOPI)
Пример #6
0
 def _actionsFreqsAngles(self,*args,**kwargs):
     """
     NAME:
        actionsFreqsAngles (_actionsFreqsAngles)
     PURPOSE:
        evaluate the actions, frequencies, and angles (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     INPUT:
        Either:
           a) R,vR,vT,z,vz[,phi]:
              1) floats: phase-space value for single object (phi is optional) (each can be a Quantity)
              2) numpy.ndarray: [N] phase-space values for N objects (each can be a Quantity)
           b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well as the second argument
        maxn= (default: object-wide default) Use a grid in vec(n) up to this n (zero-based)
        ts= if set, the phase-space points correspond to these times (IF NOT SET, WE ASSUME THAT ts IS THAT THAT IS ASSOCIATED WITH THIS OBJECT)
        _firstFlip= (False) if True and Orbits are given, the backward part of the orbit is integrated first and stored in the Orbit object
     OUTPUT:
         (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez)
     HISTORY:
        2013-09-10 - Written - Bovy (IAS)
     """
     from galpy.orbit import Orbit
     _firstFlip= kwargs.get('_firstFlip',False)
     #If the orbit was already integrated, set ts to the integration times
     if isinstance(args[0],Orbit) and hasattr(args[0]._orb,'orbit') \
             and not 'ts' in kwargs:
         kwargs['ts']= args[0]._orb.t
     elif (isinstance(args[0],list) and isinstance(args[0][0],Orbit)) \
             and hasattr(args[0][0]._orb,'orbit')  \
             and not 'ts' in kwargs:
         kwargs['ts']= args[0][0]._orb.t
     R,vR,vT,z,vz,phi= self._parse_args(True,_firstFlip,*args)
     if 'ts' in kwargs and not kwargs['ts'] is None:
         ts= kwargs['ts']
         if _APY_LOADED and isinstance(ts,units.Quantity):
             ts= ts.to(units.Gyr).value\
                 /time_in_Gyr(self._vo,self._ro)
     else:
         ts= nu.empty(R.shape[1])
         ts[self._ntintJ-1:]= self._tsJ
         ts[:self._ntintJ-1]= -self._tsJ[1:][::-1]
     maxn= kwargs.get('maxn',self._maxn)
     if self._c: #pragma: no cover
         pass
     else:
         #Use self._aAI to calculate the actions and angles in the isochrone potential
         if '_acfs' in kwargs: acfs= kwargs['_acfs']
         else:
             acfs= self._aAI._actionsFreqsAngles(R.flatten(),
                                                 vR.flatten(),
                                                 vT.flatten(),
                                                 z.flatten(),
                                                 vz.flatten(),
                                                 phi.flatten())
         jrI= nu.reshape(acfs[0],R.shape)[:,:-1]
         jzI= nu.reshape(acfs[2],R.shape)[:,:-1]
         anglerI= nu.reshape(acfs[6],R.shape)
         anglezI= nu.reshape(acfs[8],R.shape)
         if nu.any((nu.fabs(nu.amax(anglerI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglerI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full radial angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         if nu.any((nu.fabs(nu.amax(anglezI,axis=1)-_TWOPI) > _ANGLETOL)\
                       *(nu.fabs(nu.amin(anglezI,axis=1)) > _ANGLETOL)): #pragma: no cover
             warnings.warn("Full vertical angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
         danglerI= ((nu.roll(anglerI,-1,axis=1)-anglerI) % _TWOPI)[:,:-1]
         danglezI= ((nu.roll(anglezI,-1,axis=1)-anglezI) % _TWOPI)[:,:-1]
         jr= nu.sum(jrI*danglerI,axis=1)/nu.sum(danglerI,axis=1)
         jz= nu.sum(jzI*danglezI,axis=1)/nu.sum(danglezI,axis=1)
         if _isNonAxi(self._pot): #pragma: no cover
             lzI= nu.reshape(acfs[1],R.shape)[:,:-1]
             anglephiI= nu.reshape(acfs[7],R.shape)
             if nu.any((nu.fabs(nu.amax(anglephiI,axis=1)-_TWOPI) > _ANGLETOL)\
                           *(nu.fabs(nu.amin(anglephiI,axis=1)) > _ANGLETOL)): #pragma: no cover
                 warnings.warn("Full azimuthal angle range not covered for at least one object; actions are likely not reliable",galpyWarning)
             danglephiI= ((nu.roll(anglephiI,-1,axis=1)-anglephiI) % _TWOPI)[:,:-1]
             lz= nu.sum(lzI*danglephiI,axis=1)/nu.sum(danglephiI,axis=1)
         else:
             lz= R[:,len(ts)//2]*vT[:,len(ts)//2]
         #Now do an 'angle-fit'
         angleRT= dePeriod(nu.reshape(acfs[6],R.shape))
         acfs7= nu.reshape(acfs[7],R.shape)
         negFreqIndx= nu.median(acfs7-nu.roll(acfs7,1,axis=1),axis=1) < 0. #anglephi is decreasing
         anglephiT= nu.empty(acfs7.shape)
         anglephiT[negFreqIndx,:]= dePeriod(_TWOPI-acfs7[negFreqIndx,:])
         negFreqPhi= nu.zeros(R.shape[0],dtype='bool')
         negFreqPhi[negFreqIndx]= True
         anglephiT[True^negFreqIndx,:]= dePeriod(acfs7[True^negFreqIndx,:])
         angleZT= dePeriod(nu.reshape(acfs[8],R.shape))
         #Write the angle-fit as Y=AX, build A and Y
         nt= len(ts)
         no= R.shape[0]
         #remove 0,0,0 and half-plane
         if _isNonAxi(self._pot):
             nn= (2*maxn-1)**2*maxn-(maxn-1)*(2*maxn-1)-maxn
         else:
             nn= maxn*(2*maxn-1)-maxn 
         A= nu.zeros((no,nt,2+nn))
         A[:,:,0]= 1.
         A[:,:,1]= ts
         #sorting the phi and Z grids this way makes it easy to exclude the origin
         phig= list(nu.arange(-maxn+1,maxn,1))
         phig.sort(key = lambda x: abs(x))
         phig= nu.array(phig,dtype='int')
         if _isNonAxi(self._pot):
             grid= nu.meshgrid(nu.arange(maxn),phig,phig)
         else:
             grid= nu.meshgrid(nu.arange(maxn),phig)
         gridR= grid[0].T.flatten()[1:] #remove 0,0,0
         gridZ= grid[1].T.flatten()[1:]
         mask = nu.ones(len(gridR),dtype=bool)
         # excludes axis that is not in half-space
         if _isNonAxi(self._pot):
             gridphi= grid[2].T.flatten()[1:]
             mask= True\
                 ^(gridR == 0)*((gridphi < 0)+((gridphi==0)*(gridZ < 0)))
         else:
             mask[:2*maxn-3:2]= False
         gridR= gridR[mask]
         gridZ= gridZ[mask]
         tangleR= nu.tile(angleRT.T,(nn,1,1)).T
         tgridR= nu.tile(gridR,(no,nt,1))
         tangleZ= nu.tile(angleZT.T,(nn,1,1)).T
         tgridZ= nu.tile(gridZ,(no,nt,1))
         if _isNonAxi(self._pot):
             gridphi= gridphi[mask]
             tgridphi= nu.tile(gridphi,(no,nt,1))
             tanglephi= nu.tile(anglephiT.T,(nn,1,1)).T
             sinnR= nu.sin(tgridR*tangleR+tgridphi*tanglephi+tgridZ*tangleZ)
         else:
             sinnR= nu.sin(tgridR*tangleR+tgridZ*tangleZ)
         A[:,:,2:]= sinnR
         #Matrix magic
         atainv= nu.empty((no,2+nn,2+nn))
         AT= nu.transpose(A,axes=(0,2,1))
         for ii in range(no):
             atainv[ii,:,:,]= linalg.inv(nu.dot(AT[ii,:,:],A[ii,:,:]))
         ATAR= nu.sum(AT*nu.transpose(nu.tile(angleRT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         ATAT= nu.sum(AT*nu.transpose(nu.tile(anglephiT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         ATAZ= nu.sum(AT*nu.transpose(nu.tile(angleZT,(2+nn,1,1)),axes=(1,0,2)),axis=2)
         angleR= nu.sum(atainv[:,0,:]*ATAR,axis=1)
         OmegaR= nu.sum(atainv[:,1,:]*ATAR,axis=1)
         anglephi= nu.sum(atainv[:,0,:]*ATAT,axis=1)
         Omegaphi= nu.sum(atainv[:,1,:]*ATAT,axis=1)
         angleZ= nu.sum(atainv[:,0,:]*ATAZ,axis=1)
         OmegaZ= nu.sum(atainv[:,1,:]*ATAZ,axis=1)
         Omegaphi[negFreqIndx]= -Omegaphi[negFreqIndx]
         anglephi[negFreqIndx]= _TWOPI-anglephi[negFreqIndx]
         if kwargs.get('_retacfs',False):
             return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ, #pragma: no cover
                     angleR % _TWOPI,
                     anglephi % _TWOPI,
                     angleZ % _TWOPI,acfs)
         else:
             return (jr,lz,jz,OmegaR,Omegaphi,OmegaZ,
                     angleR % _TWOPI,
                     anglephi % _TWOPI,
                     angleZ % _TWOPI)