def actionsFreqs(self,*args,**kwargs): """ NAME: actionsFreqs PURPOSE: evaluate the actions and frequencies (jr,lz,jz,Omegar,Omegaphi,Omegaz) INPUT: Either: a) R,vR,vT,z,vz b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well scipy.integrate.quadrature keywords OUTPUT: (jr,lz,jz,Omegar,Omegaphi,Omegaz) HISTORY: 2013-08-28 - Written - Bovy (IAS) """ if ((self._c and not (kwargs.has_key('c') and not kwargs['c']))\ or (ext_loaded and ((kwargs.has_key('c') and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R,vR,vT, z, vz= args elif len(args) == 6: #R,vR.vT, z, vz, phi R,vR,vT, z, vz, phi= args else: meta= actionAngle(*args) R= meta._R vR= meta._vR vT= meta._vT z= meta._z vz= meta._vz if isinstance(R,float): R= nu.array([R]) vR= nu.array([vR]) vT= nu.array([vT]) z= nu.array([z]) vz= nu.array([vz]) Lz= R*vT if self._useu0: #First calculate u0 if kwargs.has_key('u0'): u0= kwargs['u0'] else: E= nu.array([evaluatePotentials(R[ii],z[ii],self._pot) +vR[ii]**2./2.+vz[ii]**2./2.+vT[ii]**2./2. for ii in range(len(R))]) u0= actionAngleStaeckel_c.actionAngleStaeckel_calcu0(E,Lz, self._pot, self._delta)[0] if kwargs.has_key('u0'): kwargs.pop('u0') else: u0= None jr, jz, Omegar, Omegaphi, Omegaz, err= actionAngleStaeckel_c.actionAngleFreqStaeckel_c(\ self._pot,self._delta,R,vR,vT,z,vz,u0=u0) if err == 0: return (jr,Lz,jz,Omegar,Omegaphi,Omegaz) else: raise RuntimeError("C-code for calculation actions failed; try with c=False") else: if kwargs.has_key('c') and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) raise NotImplementedError("actionsFreqs with c=False not implemented")
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleAdiabatic object INPUT: pot= potential or list of potentials (planarPotentials) gamma= (default=1.) replace Lz by Lz+gamma Jz in effective potential OUTPUT: HISTORY: 2012-07-26 - Written - Bovy (IAS@MPIA) """ if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleAxi") self._pot= kwargs['pot'] 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 and 'c' in kwargs and kwargs['c']: self._c= _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover else: self._c= False self._gamma= kwargs.get('gamma',1.) return None
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleAdiabatic object INPUT: pot= potential or list of potentials (planarPotentials) gamma= (default=1.) replace Lz by Lz+gamma Jz in effective potential OUTPUT: HISTORY: 2012-07-26 - Written - Bovy (IAS@MPIA) """ if not kwargs.has_key('pot'): #pragma: no cover raise IOError("Must specify pot= for actionAngleAxi") self._pot= kwargs['pot'] if ext_loaded and kwargs.has_key('c') and kwargs['c']: self._c= _check_c(self._pot) if kwargs.has_key('c') and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover else: self._c= False if kwargs.has_key('gamma'): self._gamma= kwargs['gamma'] else: self._gamma= 1. return None
def __init__(self, *args, **kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleStaeckel object INPUT: pot= potential or list of potentials (3D) delta= focus (can be Quantity) useu0 - use u0 to calculate dV (NOT recommended) c= if True, always use C for calculations order= (10) number of points to use in the Gauss-Legendre numerical integration of the relevant action, frequency, and angle integrals ro= distance from vantage point to GC (kpc; can be Quantity) vo= circular velocity at ro (km/s; can be Quantity) OUTPUT: instance HISTORY: 2012-11-27 - Written - Bovy (IAS) """ actionAngle.__init__(self, ro=kwargs.get('ro', None), vo=kwargs.get('vo', None)) if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleStaeckel") self._pot = kwargs['pot'] 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 not 'delta' in kwargs: #pragma: no cover raise IOError("Must specify delta= for actionAngleStaeckel") if ext_loaded and (('c' in kwargs and kwargs['c']) or not 'c' in kwargs): self._c = _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) #pragma: no cover else: self._c = False self._useu0 = kwargs.get('useu0', False) self._delta = kwargs['delta'] self._order = kwargs.get('order', 10) if _APY_LOADED and isinstance(self._delta, units.Quantity): self._delta = self._delta.to(units.kpc).value / self._ro # Check the units self._check_consistent_units() return None
def _integrateROrbit(vxvv,pot,t,method,dt): """ NAME: _integrateROrbit PURPOSE: integrate an orbit in a Phi(R) potential in the R-plane INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT]; vR outward! pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' dt - if set, force the integrator to use this basic stepsize; must be an integer divisor of output stepsize OUTPUT: [:,3] array of [R,vR,vT] at each t HISTORY: 2010-07-20 - Written - Bovy (NYU) """ #First check that the potential has C if '_c' in method: if not _check_c(pot): if ('leapfrog' in method or 'symplec' in method): method= 'leapfrog' else: method= 'odeint' warnings.warn("Cannot use C integration because some of the potentials are not implemented in C (using %s instead)" % (method), galpyWarning) if method.lower() == 'leapfrog': #We hack this by putting in a dummy phi this_vxvv= nu.zeros(len(vxvv)+1) this_vxvv[0:len(vxvv)]= vxvv tmp_out, msg= _integrateOrbit(this_vxvv,pot,t,method,dt) #tmp_out is (nt,4) out= tmp_out[:,0:3] elif method.lower() == 'leapfrog_c' or method.lower() == 'rk4_c' \ or method.lower() == 'rk6_c' or method.lower() == 'symplec4_c' \ or method.lower() == 'symplec6_c' or method.lower() == 'dopr54_c': #We hack this by putting in a dummy phi this_vxvv= nu.zeros(len(vxvv)+1) this_vxvv[0:len(vxvv)]= vxvv tmp_out, msg= _integrateOrbit(this_vxvv,pot,t,method,dt) #tmp_out is (nt,4) out= tmp_out[:,0:3] elif method.lower() == 'odeint': l= vxvv[0]*vxvv[2] l2= l**2. init= [vxvv[0],vxvv[1]] intOut= integrate.odeint(_REOM,init,t,args=(pot,l2), rtol=10.**-8.)#,mxstep=100000000) out= nu.zeros((len(t),3)) out[:,0]= intOut[:,0] out[:,1]= intOut[:,1] out[:,2]= l/out[:,0] msg= 0 #post-process to remove negative radii neg_radii= (out[:,0] < 0.) out[neg_radii,0]= -out[neg_radii,0] _parse_warnmessage(msg) return (out,msg)
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleStaeckel object INPUT: pot= potential or list of potentials (3D) delta= focus (can be Quantity) useu0 - use u0 to calculate dV (NOT recommended) c= if True, always use C for calculations ro= distance from vantage point to GC (kpc; can be Quantity) vo= circular velocity at ro (km/s; can be Quantity) OUTPUT: instance HISTORY: 2012-11-27 - Written - Bovy (IAS) """ actionAngle.__init__(self, ro=kwargs.get('ro',None),vo=kwargs.get('vo',None)) if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleStaeckel") self._pot= kwargs['pot'] 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 not 'delta' in kwargs: #pragma: no cover raise IOError("Must specify delta= for actionAngleStaeckel") if ext_loaded and (('c' in kwargs and kwargs['c']) or not 'c' in kwargs): self._c= _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover else: self._c= False self._useu0= kwargs.get('useu0',False) self._delta= kwargs['delta'] if _APY_LOADED and isinstance(self._delta,units.Quantity): self._delta= self._delta.to(units.kpc).value/self._ro # Check the units self._check_consistent_units() return None
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 __init__(self, *args, **kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleAdiabatic object INPUT: pot= potential or list of potentials (planarPotentials) gamma= (default=1.) replace Lz by Lz+gamma Jz in effective potential ro= distance from vantage point to GC (kpc; can be Quantity) vo= circular velocity at ro (km/s; can be Quantity) OUTPUT: instance HISTORY: 2012-07-26 - Written - Bovy (IAS@MPIA) """ actionAngle.__init__(self, ro=kwargs.get('ro', None), vo=kwargs.get('vo', None)) if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleAxi") self._pot = flatten_potential(kwargs['pot']) 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 and 'c' in kwargs and kwargs['c']: self._c = _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) #pragma: no cover else: self._c = False self._gamma = kwargs.get('gamma', 1.) # Check the units self._check_consistent_units() return None
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleAdiabatic object INPUT: pot= potential or list of potentials (planarPotentials) gamma= (default=1.) replace Lz by Lz+gamma Jz in effective potential ro= distance from vantage point to GC (kpc; can be Quantity) vo= circular velocity at ro (km/s; can be Quantity) OUTPUT: instance HISTORY: 2012-07-26 - Written - Bovy (IAS@MPIA) """ actionAngle.__init__(self, ro=kwargs.get('ro',None),vo=kwargs.get('vo',None)) if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleAxi") self._pot= flatten_potential(kwargs['pot']) 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 and 'c' in kwargs and kwargs['c']: self._c= _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover else: self._c= False self._gamma= kwargs.get('gamma',1.) # Check the units self._check_consistent_units() return None
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 __init__(self, *args, **kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleStaeckel object INPUT: pot= potential or list of potentials (3D) delta= focus useu0 - use u0 to calculate dV (NOT recommended) c= if True, always use C for calculations OUTPUT: HISTORY: 2012-11-27 - Written - Bovy (IAS) """ if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleStaeckel") self._pot = kwargs['pot'] 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 not 'delta' in kwargs: #pragma: no cover raise IOError("Must specify delta= for actionAngleStaeckel") if ext_loaded and (('c' in kwargs and kwargs['c']) or not 'c' in kwargs): self._c = _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) #pragma: no cover else: self._c = False self._useu0 = kwargs.get('useu0', False) self._delta = kwargs['delta'] return None
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleStaeckel object INPUT: pot= potential or list of potentials (3D) delta= focus useu0 - use u0 to calculate dV (NOT recommended) c= if True, always use C for calculations OUTPUT: HISTORY: 2012-11-27 - Written - Bovy (IAS) """ if not kwargs.has_key('pot'): raise IOError("Must specify pot= for actionAngleStaeckel") self._pot= kwargs['pot'] if not kwargs.has_key('delta'): raise IOError("Must specify delta= for actionAngleStaeckel") if ext_loaded and ((kwargs.has_key('c') and kwargs['c']) or not kwargs.has_key('c')): self._c= _check_c(self._pot) if kwargs.has_key('c') and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) else: self._c= False if kwargs.has_key('useu0') and kwargs['useu0']: self._useu0= True else: self._useu0= False self._delta= kwargs['delta'] return None
def __init__(self,*args,**kwargs): """ NAME: __init__ PURPOSE: initialize an actionAngleStaeckel object INPUT: pot= potential or list of potentials (3D) delta= focus useu0 - use u0 to calculate dV (NOT recommended) c= if True, always use C for calculations OUTPUT: HISTORY: 2012-11-27 - Written - Bovy (IAS) """ if not 'pot' in kwargs: #pragma: no cover raise IOError("Must specify pot= for actionAngleStaeckel") self._pot= kwargs['pot'] 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 not 'delta' in kwargs: #pragma: no cover raise IOError("Must specify delta= for actionAngleStaeckel") if ext_loaded and (('c' in kwargs and kwargs['c']) or not 'c' in kwargs): self._c= _check_c(self._pot) if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover else: self._c= False self._useu0= kwargs.get('useu0',False) self._delta= kwargs['delta'] return None
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 delta= (object-wide default) can be used to override the object-wide focal length; can also be an array with length N to allow different delta for different phase-space points u0= (None) if object-wide option useu0 is set, u0 to use (if useu0 and useu0 is None, a good value will be computed) c= (object-wide default, bool) True/False to override the object-wide setting for whether or not to use the C implementation order= (object-wide default, int) number of points to use in the Gauss-Legendre numerical integration of the relevant action integrals When not using C: fixed_quad= (False) if True, use Gaussian quadrature (scipy.integrate.fixed_quad instead of scipy.integrate.quad) scipy.integrate.fixed_quad or .quad keywords OUTPUT: (jr,lz,jz) HISTORY: 2012-11-27 - Written - Bovy (IAS) 2017-12-27 - Allowed individual delta for each point - Bovy (UofT) """ delta = kwargs.pop('delta', self._delta) order = kwargs.get('order', self._order) if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R, vR, vT, z, vz = args elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: self._parse_eval_args(*args) R = self._eval_R vR = self._eval_vR vT = self._eval_vT z = self._eval_z vz = self._eval_vz if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) Lz = R * vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0 = nu.asarray(kwargs['u0']) else: E = nu.array([ _evaluatePotentials(self._pot, R[ii], z[ii]) + vR[ii]**2. / 2. + vz[ii]**2. / 2. + vT[ii]**2. / 2. for ii in range(len(R)) ]) u0= actionAngleStaeckel_c.actionAngleStaeckel_calcu0(\ E,Lz,self._pot,delta)[0] kwargs.pop('u0', None) else: u0 = None jr, jz, err= actionAngleStaeckel_c.actionAngleStaeckel_c(\ self._pot,delta,R,vR,vT,z,vz,u0=u0,order=order) if err == 0: return (jr, Lz, jz) else: #pragma: no cover raise RuntimeError( "C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) kwargs.pop('c', None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): ojr = nu.zeros((len(args[0]))) olz = nu.zeros((len(args[0]))) ojz = nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii]) elif len(args) == 6: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii], args[5][ii]) tkwargs = copy.copy(kwargs) try: tkwargs['delta'] = delta[ii] except TypeError: tkwargs['delta'] = delta tjr, tlz, tjz = self(*targs, **tkwargs) ojr[ii] = tjr ojz[ii] = tjz olz[ii] = tlz return (ojr, olz, ojz) else: #Set up the actionAngleStaeckelSingle object aASingle = actionAngleStaeckelSingle(*args, pot=self._pot, delta=delta) return (aASingle.JR(**copy.copy(kwargs)), aASingle._R * aASingle._vT, aASingle.Jz(**copy.copy(kwargs)))
def _uminumaxvmin(self, *args, **kwargs): """ NAME: _uminumaxvmin PURPOSE: evaluate u_min, u_max, and v_min INPUT: Either: a) R,vR,vT,z,vz b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well c= True/False; overrides the object's c= keyword to use C or not OUTPUT: (umin,umax,vmin) HISTORY: 2017-12-12 - Written - Bovy (UofT) """ delta = kwargs.pop('delta', self._delta) if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R, vR, vT, z, vz = args elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: self._parse_eval_args(*args) R = self._eval_R vR = self._eval_vR vT = self._eval_vT z = self._eval_z vz = self._eval_vz if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) Lz = R * vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0 = nu.asarray(kwargs['u0']) else: E = nu.array([ _evaluatePotentials(self._pot, R[ii], z[ii]) + vR[ii]**2. / 2. + vz[ii]**2. / 2. + vT[ii]**2. / 2. for ii in range(len(R)) ]) u0= actionAngleStaeckel_c.actionAngleStaeckel_calcu0(\ E,Lz,self._pot,delta)[0] kwargs.pop('u0', None) else: u0 = None umin, umax, vmin, err= \ actionAngleStaeckel_c.actionAngleUminUmaxVminStaeckel_c(\ self._pot,delta,R,vR,vT,z,vz,u0=u0) if err == 0: return (umin, umax, vmin) else: #pragma: no cover raise RuntimeError( "C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) kwargs.pop('c', None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): oumin = nu.zeros((len(args[0]))) oumax = nu.zeros((len(args[0]))) ovmin = nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii]) elif len(args) == 6: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii], args[5][ii]) tkwargs = copy.copy(kwargs) try: tkwargs['delta'] = delta[ii] except TypeError: tkwargs['delta'] = delta tumin,tumax,tvmin= self._uminumaxvmin(\ *targs,**tkwargs) oumin[ii] = tumin oumax[ii] = tumax ovmin[ii] = tvmin return (oumin, oumax, ovmin) else: #Set up the actionAngleStaeckelSingle object aASingle = actionAngleStaeckelSingle(*args, pot=self._pot, delta=delta) umin, umax = aASingle.calcUminUmax() vmin = aASingle.calcVmin() return (umin, umax, vmin)
def _integrateOrbit_dxdv(vxvv,dxdv,pot,t,method,rectIn,rectOut): """ NAME: _integrateOrbit_dxdv PURPOSE: integrate an orbit and area of phase space in a Phi(R) potential in the (R,phi)-plane INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT,phi]; vR outward! dxdv - difference to integrate [dR,dvR,dvT,dphi] pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' rectIn= (False) if True, input dxdv is in rectangular coordinates rectOut= (False) if True, output dxdv (that in orbit_dxdv) is in rectangular coordinates OUTPUT: [:,8] array of [R,vR,vT,phi,dR,dvR,dvT,dphi] at each t error message from integrator HISTORY: 2010-10-17 - Written - Bovy (IAS) """ #First check that the potential has C if '_c' in method: allHasC= _check_c(pot) and _check_c(pot,dxdv=True) if not allHasC and not 'leapfrog' in method and not 'symplec' in method: method= 'odeint' warnings.warn("Using odeint because not all used potential have adequate C implementations to integrate phase-space volumes",galpyWarning) #go to the rectangular frame this_vxvv= nu.array([vxvv[0]*nu.cos(vxvv[3]), vxvv[0]*nu.sin(vxvv[3]), vxvv[1]*nu.cos(vxvv[3])-vxvv[2]*nu.sin(vxvv[3]), vxvv[2]*nu.cos(vxvv[3])+vxvv[1]*nu.sin(vxvv[3])]) if not rectIn: this_dxdv= nu.array([nu.cos(vxvv[3])*dxdv[0] -vxvv[0]*nu.sin(vxvv[3])*dxdv[3], nu.sin(vxvv[3])*dxdv[0] +vxvv[0]*nu.cos(vxvv[3])*dxdv[3], -(vxvv[1]*nu.sin(vxvv[3]) +vxvv[2]*nu.cos(vxvv[3]))*dxdv[3] +nu.cos(vxvv[3])*dxdv[1]-nu.sin(vxvv[3])*dxdv[2], (vxvv[1]*nu.cos(vxvv[3]) -vxvv[2]*nu.sin(vxvv[3]))*dxdv[3] +nu.sin(vxvv[3])*dxdv[1]+nu.cos(vxvv[3])*dxdv[2]]) else: this_dxdv= dxdv if 'leapfrog' in method.lower() or 'symplec' in method.lower(): raise TypeError('Symplectic integration for phase-space volume is not possible') elif method.lower() == 'rk4_c' or method.lower() == 'rk6_c' \ or method.lower() == 'dopr54_c': warnings.warn("Using C implementation to integrate orbits",galpyWarning) #integrate tmp_out, msg= integratePlanarOrbit_dxdv_c(pot,this_vxvv,this_dxdv, t,method) elif method.lower() == 'odeint': init= [this_vxvv[0],this_vxvv[1],this_vxvv[2],this_vxvv[3], this_dxdv[0],this_dxdv[1],this_dxdv[2],this_dxdv[3]] #integrate tmp_out= integrate.odeint(_EOM_dxdv,init,t,args=(pot,), rtol=10.**-8.)#,mxstep=100000000) msg= 0 else: raise NotImplementedError("requested integration method does not exist") #go back to the cylindrical frame R= nu.sqrt(tmp_out[:,0]**2.+tmp_out[:,1]**2.) phi= nu.arccos(tmp_out[:,0]/R) phi[(tmp_out[:,1] < 0.)]= 2.*nu.pi-phi[(tmp_out[:,1] < 0.)] vR= tmp_out[:,2]*nu.cos(phi)+tmp_out[:,3]*nu.sin(phi) vT= tmp_out[:,3]*nu.cos(phi)-tmp_out[:,2]*nu.sin(phi) cp= nu.cos(phi) sp= nu.sin(phi) dR= cp*tmp_out[:,4]+sp*tmp_out[:,5] dphi= (cp*tmp_out[:,5]-sp*tmp_out[:,4])/R dvR= cp*tmp_out[:,6]+sp*tmp_out[:,7]+vT*dphi dvT= cp*tmp_out[:,7]-sp*tmp_out[:,6]-vR*dphi out= nu.zeros((len(t),8)) out[:,0]= R out[:,1]= vR out[:,2]= vT out[:,3]= phi if rectOut: out[:,4:]= tmp_out[:,4:] else: out[:,4]= dR out[:,7]= dphi out[:,5]= dvR out[:,6]= dvT _parse_warnmessage(msg) return (out,msg)
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 delta= (object-wide default) can be used to override the object-wide focal length; can also be an array with length N to allow different delta for different phase-space points u0= (None) if object-wide option useu0 is set, u0 to use (if useu0 and useu0 is None, a good value will be computed) c= (object-wide default, bool) True/False to override the object-wide setting for whether or not to use the C implementation order= (10) number of points to use in the Gauss-Legendre numerical integration of the relevant action, frequency, and angle integrals When not using C: fixed_quad= (False) if True, use Gaussian quadrature (scipy.integrate.fixed_quad instead of scipy.integrate.quad) scipy.integrate.fixed_quad or .quad keywords OUTPUT: (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) HISTORY: 2013-08-28 - Written - Bovy (IAS) """ delta = kwargs.pop('delta', self._delta) order = kwargs.get('order', self._order) if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz pragma: no cover raise IOError("Must specify phi") elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: self._parse_eval_args(*args) R = self._eval_R vR = self._eval_vR vT = self._eval_vT z = self._eval_z vz = self._eval_vz phi = self._eval_phi if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) phi = nu.array([phi]) Lz = R * vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0 = nu.asarray(kwargs['u0']) else: E = nu.array([ _evaluatePotentials(self._pot, R[ii], z[ii]) + vR[ii]**2. / 2. + vz[ii]**2. / 2. + vT[ii]**2. / 2. for ii in range(len(R)) ]) u0= actionAngleStaeckel_c.actionAngleStaeckel_calcu0(\ E,Lz,self._pot,delta)[0] kwargs.pop('u0', None) else: u0 = None jr, jz, Omegar, Omegaphi, Omegaz, angler, anglephi,anglez, err= actionAngleStaeckel_c.actionAngleFreqAngleStaeckel_c(\ self._pot,delta,R,vR,vT,z,vz,phi,u0=u0,order=order) # Adjustements for close-to-circular orbits indx = nu.isnan(Omegar) * (jr < 10.**-3.) + nu.isnan(Omegaz) * ( jz < 10.**-3. ) #Close-to-circular and close-to-the-plane orbits if nu.sum(indx) > 0: Omegar[indx] = [ epifreq(self._pot, r, use_physical=False) for r in R[indx] ] Omegaphi[indx] = [ omegac(self._pot, r, use_physical=False) for r in R[indx] ] Omegaz[indx] = [ verticalfreq(self._pot, r, use_physical=False) for r in R[indx] ] if err == 0: return (jr, Lz, jz, Omegar, Omegaphi, Omegaz, angler, anglephi, anglez) else: raise RuntimeError( "C-code for calculation actions failed; try with c=False" ) #pragma: no cover else: #pragma: no cover if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) raise NotImplementedError( "actionsFreqs with c=False not implemented")
def __call__(self, *args, **kwargs): """ NAME: __call__ PURPOSE: evaluate the actions (jr,lz,jz) INPUT: Either: a) R,vR,vT,z,vz b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well c= True/False; overrides the object's c= keyword to use C or not scipy.integrate.quadrature keywords OUTPUT: (jr,lz,jz) HISTORY: 2012-11-27 - Written - Bovy (IAS) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R, vR, vT, z, vz = args elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: meta = actionAngle(*args) R = meta._R vR = meta._vR vT = meta._vT z = meta._z vz = meta._vz if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) Lz = R * vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0 = nu.asarray(kwargs['u0']) else: E = nu.array([ evaluatePotentials(R[ii], z[ii], self._pot) + vR[ii]**2. / 2. + vz[ii]**2. / 2. + vT[ii]**2. / 2. for ii in range(len(R)) ]) u0 = actionAngleStaeckel_c.actionAngleStaeckel_calcu0( E, Lz, self._pot, self._delta)[0] kwargs.pop('u0', None) else: u0 = None jr, jz, err= actionAngleStaeckel_c.actionAngleStaeckel_c(\ self._pot,self._delta,R,vR,vT,z,vz,u0=u0) if err == 0: return (jr, Lz, jz) else: #pragma: no cover raise RuntimeError( "C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) kwargs.pop('c', None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): ojr = nu.zeros((len(args[0]))) olz = nu.zeros((len(args[0]))) ojz = nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii]) elif len(args) == 6: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii], args[5][ii]) tjr, tlz, tjz = self(*targs, **copy.copy(kwargs)) ojr[ii] = tjr ojz[ii] = tjz olz[ii] = tlz return (ojr, olz, ojz) else: #Set up the actionAngleStaeckelSingle object aASingle = actionAngleStaeckelSingle(*args, pot=self._pot, delta=self._delta) return (aASingle.JR(**copy.copy(kwargs)), aASingle._R * aASingle._vT, aASingle.Jz(**copy.copy(kwargs)))
def _integrateFullOrbit(vxvv, pot, t, method, dt): """ NAME: _integrateFullOrbit PURPOSE: integrate an orbit in a Phi(R,z,phi) potential INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT,z,vz,phi]; vR outward! pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' dt - if set, force the integrator to use this basic stepsize; must be an integer divisor of output stepsize OUTPUT: [:,5] array of [R,vR,vT,z,vz,phi] at each t HISTORY: 2010-08-01 - Written - Bovy (NYU) """ #First check that the potential has C if '_c' in method: if not ext_loaded or not _check_c(pot): if ('leapfrog' in method or 'symplec' in method): method = 'leapfrog' else: method = 'odeint' if not ext_loaded: # pragma: no cover warnings.warn( "Cannot use C integration because C extension not loaded (using %s instead)" % (method), galpyWarning) else: warnings.warn( "Cannot use C integration because some of the potentials are not implemented in C (using %s instead)" % (method), galpyWarning) if method.lower() == 'leapfrog': #go to the rectangular frame this_vxvv = nu.array([ vxvv[0] * nu.cos(vxvv[5]), vxvv[0] * nu.sin(vxvv[5]), vxvv[3], vxvv[1] * nu.cos(vxvv[5]) - vxvv[2] * nu.sin(vxvv[5]), vxvv[2] * nu.cos(vxvv[5]) + vxvv[1] * nu.sin(vxvv[5]), vxvv[4] ]) #integrate out = symplecticode.leapfrog(_rectForce, this_vxvv, t, args=(pot, ), rtol=10.**-8) #go back to the cylindrical frame R = nu.sqrt(out[:, 0]**2. + out[:, 1]**2.) phi = nu.arccos(out[:, 0] / R) phi[(out[:, 1] < 0.)] = 2. * nu.pi - phi[(out[:, 1] < 0.)] vR = out[:, 3] * nu.cos(phi) + out[:, 4] * nu.sin(phi) vT = out[:, 4] * nu.cos(phi) - out[:, 3] * nu.sin(phi) out[:, 3] = out[:, 2] out[:, 4] = out[:, 5] out[:, 0] = R out[:, 1] = vR out[:, 2] = vT out[:, 5] = phi elif ext_loaded and \ (method.lower() == 'leapfrog_c' or method.lower() == 'rk4_c' \ or method.lower() == 'rk6_c' or method.lower() == 'symplec4_c' \ or method.lower() == 'symplec6_c' or method.lower() == 'dopr54_c'): warnings.warn("Using C implementation to integrate orbits", galpyWarningVerbose) #go to the rectangular frame this_vxvv = nu.array([ vxvv[0] * nu.cos(vxvv[5]), vxvv[0] * nu.sin(vxvv[5]), vxvv[3], vxvv[1] * nu.cos(vxvv[5]) - vxvv[2] * nu.sin(vxvv[5]), vxvv[2] * nu.cos(vxvv[5]) + vxvv[1] * nu.sin(vxvv[5]), vxvv[4] ]) #integrate tmp_out, msg = integrateFullOrbit_c(pot, this_vxvv, t, method, dt=dt) #go back to the cylindrical frame R = nu.sqrt(tmp_out[:, 0]**2. + tmp_out[:, 1]**2.) phi = nu.arccos(tmp_out[:, 0] / R) phi[(tmp_out[:, 1] < 0.)] = 2. * nu.pi - phi[(tmp_out[:, 1] < 0.)] vR = tmp_out[:, 3] * nu.cos(phi) + tmp_out[:, 4] * nu.sin(phi) vT = tmp_out[:, 4] * nu.cos(phi) - tmp_out[:, 3] * nu.sin(phi) out = nu.zeros((len(t), 6)) out[:, 0] = R out[:, 1] = vR out[:, 2] = vT out[:, 5] = phi out[:, 3] = tmp_out[:, 2] out[:, 4] = tmp_out[:, 5] elif method.lower() == 'odeint' or not ext_loaded: vphi = vxvv[2] / vxvv[0] init = [vxvv[0], vxvv[1], vxvv[5], vphi, vxvv[3], vxvv[4]] intOut = integrate.odeint(_FullEOM, init, t, args=(pot, ), rtol=10.**-8.) #,mxstep=100000000) out = nu.zeros((len(t), 6)) out[:, 0] = intOut[:, 0] out[:, 1] = intOut[:, 1] out[:, 2] = out[:, 0] * intOut[:, 3] out[:, 3] = intOut[:, 4] out[:, 4] = intOut[:, 5] out[:, 5] = intOut[:, 2] #post-process to remove negative radii neg_radii = (out[:, 0] < 0.) out[neg_radii, 0] = -out[neg_radii, 0] out[neg_radii, 5] += m.pi return out
def _evaluate(self, *args, **kwargs): """ NAME: _evaluate PURPOSE: evaluate the actions (jr,lz,jz) INPUT: Either: a) R,vR,vT,z,vz b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well scipy.integrate.quadrature keywords _justjr, _justjz= if True, only calculate the radial or vertical action (internal use) OUTPUT: (jr,lz,jz), where jr=[jr,jrerr], and jz=[jz,jzerr] HISTORY: 2012-07-26 - Written - Bovy (IAS@MPIA) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R, vR, vT, z, vz = args elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: self._parse_eval_args(*args) R = self._eval_R vR = self._eval_vR vT = self._eval_vT z = self._eval_z vz = self._eval_vz if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) Lz = R * vT jr, jz, err= actionAngleAdiabatic_c.actionAngleAdiabatic_c(\ self._pot,self._gamma,R,vR,vT,z,vz) if err == 0: return (jr, Lz, jz) else: #pragma: no cover raise RuntimeError( "C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) #pragma: no cover kwargs.pop('c', None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): ojr = nu.zeros((len(args[0]))) olz = nu.zeros((len(args[0]))) ojz = nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii]) elif len(args) == 6: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii], args[5][ii]) tjr, tlz, tjz = self(*targs, **copy.copy(kwargs)) ojr[ii] = tjr ojz[ii] = tjz olz[ii] = tlz return (ojr, olz, ojz) else: #Set up the actionAngleAxi object self._parse_eval_args(*args) if isinstance(self._pot, list): thispot = [p.toPlanar() for p in self._pot] else: thispot = self._pot.toPlanar() if isinstance(self._pot, list): thisverticalpot = [ p.toVertical(self._eval_R) for p in self._pot ] else: thisverticalpot = self._pot.toVertical(self._eval_R) aAAxi = actionAngleAxi(*args, pot=thispot, verticalPot=thisverticalpot, gamma=self._gamma) if kwargs.get('_justjr', False): kwargs.pop('_justjr') return (aAAxi.JR(**kwargs), nu.nan, nu.nan) elif kwargs.get('_justjz', False): kwargs.pop('_justjz') return (nu.nan, nu.nan, aAAxi.Jz(**kwargs)) else: return (aAAxi.JR(**kwargs), aAAxi._R * aAAxi._vT, aAAxi.Jz(**kwargs))
def _EccZmaxRperiRap(self, *args, **kwargs): """ NAME: EccZmaxRperiRap (_EccZmaxRperiRap) PURPOSE: evaluate the eccentricity, maximum height above the plane, peri- and apocenter in the adiabatic approximation 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 c= (object-wide default, bool) True/False to override the object-wide setting for whether or not to use the C implementation OUTPUT: (e,zmax,rperi,rap) HISTORY: 2017-12-21 - Written - Bovy (UofT) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R, vR, vT, z, vz = args elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: self._parse_eval_args(*args) R = self._eval_R vR = self._eval_vR vT = self._eval_vT z = self._eval_z vz = self._eval_vz if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) rperi,Rap,zmax, err= actionAngleAdiabatic_c.actionAngleRperiRapZmaxAdiabatic_c(\ self._pot,self._gamma,R,vR,vT,z,vz) if err == 0: rap = nu.sqrt(Rap**2. + zmax**2.) ecc = (rap - rperi) / (rap + rperi) return (ecc, zmax, rperi, rap) else: #pragma: no cover raise RuntimeError( "C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) #pragma: no cover kwargs.pop('c', None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): oecc = nu.zeros((len(args[0]))) orperi = nu.zeros((len(args[0]))) orap = nu.zeros((len(args[0]))) ozmax = nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii]) elif len(args) == 6: targs = (args[0][ii], args[1][ii], args[2][ii], args[3][ii], args[4][ii], args[5][ii]) tecc, tzmax, trperi,trap= self._EccZmaxRperiRap(\ *targs,**copy.copy(kwargs)) oecc[ii] = tecc ozmax[ii] = tzmax orperi[ii] = trperi orap[ii] = trap return (oecc, ozmax, orperi, orap) else: #Set up the actionAngleAxi object self._parse_eval_args(*args) if isinstance(self._pot, list): thispot = [p.toPlanar() for p in self._pot] else: thispot = self._pot.toPlanar() if isinstance(self._pot, list): thisverticalpot = [ p.toVertical(self._eval_R) for p in self._pot ] else: thisverticalpot = self._pot.toVertical(self._eval_R) aAAxi = actionAngleAxi(*args, pot=thispot, verticalPot=thisverticalpot, gamma=self._gamma) rperi, Rap = aAAxi.calcRapRperi(**kwargs) zmax = aAAxi.calczmax(**kwargs) rap = nu.sqrt(Rap**2. + zmax**2.) return ((rap - rperi) / (rap + rperi), zmax, rperi, rap)
def _EccZmaxRperiRap(self,*args,**kwargs): """ NAME: EccZmaxRperiRap (_EccZmaxRperiRap) PURPOSE: evaluate the eccentricity, maximum height above the plane, peri- and apocenter in the adiabatic approximation 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 c= (object-wide default, bool) True/False to override the object-wide setting for whether or not to use the C implementation OUTPUT: (e,zmax,rperi,rap) HISTORY: 2017-12-21 - Written - Bovy (UofT) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R,vR,vT, z, vz= args elif len(args) == 6: #R,vR.vT, z, vz, phi R,vR,vT, z, vz, phi= args else: self._parse_eval_args(*args) R= self._eval_R vR= self._eval_vR vT= self._eval_vT z= self._eval_z vz= self._eval_vz if isinstance(R,float): R= nu.array([R]) vR= nu.array([vR]) vT= nu.array([vT]) z= nu.array([z]) vz= nu.array([vz]) rperi,Rap,zmax, err= actionAngleAdiabatic_c.actionAngleRperiRapZmaxAdiabatic_c(\ self._pot,self._gamma,R,vR,vT,z,vz) if err == 0: rap= nu.sqrt(Rap**2.+zmax**2.) ecc= (rap-rperi)/(rap+rperi) return (ecc,zmax,rperi,rap) else: #pragma: no cover raise RuntimeError("C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover kwargs.pop('c',None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): oecc= nu.zeros((len(args[0]))) orperi= nu.zeros((len(args[0]))) orap= nu.zeros((len(args[0]))) ozmax= nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs= (args[0][ii],args[1][ii],args[2][ii], args[3][ii],args[4][ii]) elif len(args) == 6: targs= (args[0][ii],args[1][ii],args[2][ii], args[3][ii],args[4][ii],args[5][ii]) tecc, tzmax, trperi,trap= self._EccZmaxRperiRap(\ *targs,**copy.copy(kwargs)) oecc[ii]= tecc ozmax[ii]= tzmax orperi[ii]= trperi orap[ii]= trap return (oecc,ozmax,orperi,orap) else: #Set up the actionAngleAxi object self._parse_eval_args(*args) if isinstance(self._pot,list): thispot= [p.toPlanar() for p in self._pot] else: thispot= self._pot.toPlanar() if isinstance(self._pot,list): thisverticalpot= [p.toVertical(self._eval_R) for p in self._pot] else: thisverticalpot= self._pot.toVertical(self._eval_R) aAAxi= actionAngleAxi(*args,pot=thispot, verticalPot=thisverticalpot, gamma=self._gamma) rperi,Rap= aAAxi.calcRapRperi(**kwargs) zmax= aAAxi.calczmax(**kwargs) rap= nu.sqrt(Rap**2.+zmax**2.) return ((rap-rperi)/(rap+rperi),zmax,rperi,rap)
def _evaluate(self,*args,**kwargs): """ NAME: _evaluate PURPOSE: evaluate the actions (jr,lz,jz) INPUT: Either: a) R,vR,vT,z,vz b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well scipy.integrate.quadrature keywords _justjr, _justjz= if True, only calculate the radial or vertical action (internal use) OUTPUT: (jr,lz,jz), where jr=[jr,jrerr], and jz=[jz,jzerr] HISTORY: 2012-07-26 - Written - Bovy (IAS@MPIA) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R,vR,vT, z, vz= args elif len(args) == 6: #R,vR.vT, z, vz, phi R,vR,vT, z, vz, phi= args else: self._parse_eval_args(*args) R= self._eval_R vR= self._eval_vR vT= self._eval_vT z= self._eval_z vz= self._eval_vz if isinstance(R,float): R= nu.array([R]) vR= nu.array([vR]) vT= nu.array([vT]) z= nu.array([z]) vz= nu.array([vz]) Lz= R*vT jr, jz, err= actionAngleAdiabatic_c.actionAngleAdiabatic_c(\ self._pot,self._gamma,R,vR,vT,z,vz) if err == 0: return (jr,Lz,jz) else: #pragma: no cover raise RuntimeError("C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) #pragma: no cover kwargs.pop('c',None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): ojr= nu.zeros((len(args[0]))) olz= nu.zeros((len(args[0]))) ojz= nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs= (args[0][ii],args[1][ii],args[2][ii], args[3][ii],args[4][ii]) elif len(args) == 6: targs= (args[0][ii],args[1][ii],args[2][ii], args[3][ii],args[4][ii],args[5][ii]) tjr,tlz,tjz= self(*targs,**copy.copy(kwargs)) ojr[ii]= tjr ojz[ii]= tjz olz[ii]= tlz return (ojr,olz,ojz) else: #Set up the actionAngleAxi object self._parse_eval_args(*args) if isinstance(self._pot,list): thispot= [p.toPlanar() for p in self._pot] else: thispot= self._pot.toPlanar() if isinstance(self._pot,list): thisverticalpot= [p.toVertical(self._eval_R) for p in self._pot] else: thisverticalpot= self._pot.toVertical(self._eval_R) aAAxi= actionAngleAxi(*args,pot=thispot, verticalPot=thisverticalpot, gamma=self._gamma) if kwargs.get('_justjr',False): kwargs.pop('_justjr') return (aAAxi.JR(**kwargs),nu.nan,nu.nan) elif kwargs.get('_justjz',False): kwargs.pop('_justjz') return (nu.nan,nu.nan,aAAxi.Jz(**kwargs)) else: return (aAAxi.JR(**kwargs),aAAxi._R*aAAxi._vT,aAAxi.Jz(**kwargs))
def _integrateOrbit(vxvv, pot, t, method, dt): """ NAME: _integrateOrbit PURPOSE: integrate an orbit in a Phi(R) potential in the (R,phi)-plane INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT,phi]; vR outward! pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' dt- if set, force the integrator to use this basic stepsize; must be an integer divisor of output stepsize OUTPUT: [:,4] array of [R,vR,vT,phi] at each t HISTORY: 2010-07-20 - Written - Bovy (NYU) """ #First check that the potential has C if '_c' in method: if not _check_c(pot): if ('leapfrog' in method or 'symplec' in method): method = 'leapfrog' else: method = 'odeint' warnings.warn( "Cannot use C integration because some of the potentials are not implemented in C (using %s instead)" % (method), galpyWarning) if method.lower() == 'leapfrog': #go to the rectangular frame this_vxvv = nu.array([ vxvv[0] * nu.cos(vxvv[3]), vxvv[0] * nu.sin(vxvv[3]), vxvv[1] * nu.cos(vxvv[3]) - vxvv[2] * nu.sin(vxvv[3]), vxvv[2] * nu.cos(vxvv[3]) + vxvv[1] * nu.sin(vxvv[3]) ]) #integrate tmp_out = symplecticode.leapfrog(_rectForce, this_vxvv, t, args=(pot, ), rtol=10.**-8) #go back to the cylindrical frame R = nu.sqrt(tmp_out[:, 0]**2. + tmp_out[:, 1]**2.) phi = nu.arccos(tmp_out[:, 0] / R) phi[(tmp_out[:, 1] < 0.)] = 2. * nu.pi - phi[(tmp_out[:, 1] < 0.)] vR = tmp_out[:, 2] * nu.cos(phi) + tmp_out[:, 3] * nu.sin(phi) vT = tmp_out[:, 3] * nu.cos(phi) - tmp_out[:, 2] * nu.sin(phi) out = nu.zeros((len(t), 4)) out[:, 0] = R out[:, 1] = vR out[:, 2] = vT out[:, 3] = phi msg = 0 elif method.lower() == 'leapfrog_c' or method.lower() == 'rk4_c' \ or method.lower() == 'rk6_c' or method.lower() == 'symplec4_c' \ or method.lower() == 'symplec6_c' or method.lower() == 'dopr54_c': warnings.warn("Using C implementation to integrate orbits", galpyWarningVerbose) #go to the rectangular frame this_vxvv = nu.array([ vxvv[0] * nu.cos(vxvv[3]), vxvv[0] * nu.sin(vxvv[3]), vxvv[1] * nu.cos(vxvv[3]) - vxvv[2] * nu.sin(vxvv[3]), vxvv[2] * nu.cos(vxvv[3]) + vxvv[1] * nu.sin(vxvv[3]) ]) #integrate tmp_out, msg = integratePlanarOrbit_c(pot, this_vxvv, t, method, dt=dt) #go back to the cylindrical frame R = nu.sqrt(tmp_out[:, 0]**2. + tmp_out[:, 1]**2.) phi = nu.arccos(tmp_out[:, 0] / R) phi[(tmp_out[:, 1] < 0.)] = 2. * nu.pi - phi[(tmp_out[:, 1] < 0.)] vR = tmp_out[:, 2] * nu.cos(phi) + tmp_out[:, 3] * nu.sin(phi) vT = tmp_out[:, 3] * nu.cos(phi) - tmp_out[:, 2] * nu.sin(phi) out = nu.zeros((len(t), 4)) out[:, 0] = R out[:, 1] = vR out[:, 2] = vT out[:, 3] = phi elif method.lower() == 'odeint': vphi = vxvv[2] / vxvv[0] init = [vxvv[0], vxvv[1], vxvv[3], vphi] intOut = integrate.odeint(_EOM, init, t, args=(pot, ), rtol=10.**-8.) #,mxstep=100000000) out = nu.zeros((len(t), 4)) out[:, 0] = intOut[:, 0] out[:, 1] = intOut[:, 1] out[:, 3] = intOut[:, 2] out[:, 2] = out[:, 0] * intOut[:, 3] msg = 0 else: raise NotImplementedError( "requested integration method does not exist") #post-process to remove negative radii neg_radii = (out[:, 0] < 0.) out[neg_radii, 0] = -out[neg_radii, 0] out[neg_radii, 3] += m.pi _parse_warnmessage(msg) return (out, msg)
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,phi (MUST HAVE PHI) b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well scipy.integrate.quadrature keywords OUTPUT: (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) HISTORY: 2013-08-28 - Written - Bovy (IAS) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz pragma: no cover raise IOError("Must specify phi") elif len(args) == 6: #R,vR.vT, z, vz, phi R,vR,vT, z, vz, phi= args else: self._parse_eval_args(*args) R= self._eval_R vR= self._eval_vR vT= self._eval_vT z= self._eval_z vz= self._eval_vz phi= self._eval_phi if isinstance(R,float): R= nu.array([R]) vR= nu.array([vR]) vT= nu.array([vT]) z= nu.array([z]) vz= nu.array([vz]) phi= nu.array([phi]) Lz= R*vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0= nu.asarray(kwargs['u0']) else: E= nu.array([_evaluatePotentials(self._pot,R[ii],z[ii]) +vR[ii]**2./2.+vz[ii]**2./2.+vT[ii]**2./2. for ii in range(len(R))]) u0= actionAngleStaeckel_c.actionAngleStaeckel_calcu0(E,Lz, self._pot, self._delta)[0] kwargs.pop('u0',None) else: u0= None jr, jz, Omegar, Omegaphi, Omegaz, angler, anglephi,anglez, err= actionAngleStaeckel_c.actionAngleFreqAngleStaeckel_c(\ self._pot,self._delta,R,vR,vT,z,vz,phi,u0=u0) # Adjustements for close-to-circular orbits indx= nu.isnan(Omegar)*(jr < 10.**-3.)+nu.isnan(Omegaz)*(jz < 10.**-3.) #Close-to-circular and close-to-the-plane orbits if nu.sum(indx) > 0: Omegar[indx]= [epifreq(self._pot,r,use_physical=False) for r in R[indx]] Omegaphi[indx]= [omegac(self._pot,r,use_physical=False) for r in R[indx]] Omegaz[indx]= [verticalfreq(self._pot,r,use_physical=False) for r in R[indx]] if err == 0: return (jr,Lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) else: raise RuntimeError("C-code for calculation actions failed; try with c=False") #pragma: no cover else: #pragma: no cover if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) raise NotImplementedError("actionsFreqs with c=False not implemented")
def _integrateOrbit(vxvv,pot,t,method,dt): """ NAME: _integrateOrbit PURPOSE: integrate an orbit in a Phi(R) potential in the (R,phi)-plane INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT,phi]; vR outward! pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' dt- if set, force the integrator to use this basic stepsize; must be an integer divisor of output stepsize OUTPUT: [:,4] array of [R,vR,vT,phi] at each t HISTORY: 2010-07-20 - Written - Bovy (NYU) """ #First check that the potential has C if '_c' in method: if not _check_c(pot): if ('leapfrog' in method or 'symplec' in method): method= 'leapfrog' else: method= 'odeint' warnings.warn("Cannot use C integration because some of the potentials are not implemented in C (using %s instead)" % (method), galpyWarning) if method.lower() == 'leapfrog': #go to the rectangular frame this_vxvv= nu.array([vxvv[0]*nu.cos(vxvv[3]), vxvv[0]*nu.sin(vxvv[3]), vxvv[1]*nu.cos(vxvv[3])-vxvv[2]*nu.sin(vxvv[3]), vxvv[2]*nu.cos(vxvv[3])+vxvv[1]*nu.sin(vxvv[3])]) #integrate tmp_out= symplecticode.leapfrog(_rectForce,this_vxvv, t,args=(pot,),rtol=10.**-8) #go back to the cylindrical frame R= nu.sqrt(tmp_out[:,0]**2.+tmp_out[:,1]**2.) phi= nu.arccos(tmp_out[:,0]/R) phi[(tmp_out[:,1] < 0.)]= 2.*nu.pi-phi[(tmp_out[:,1] < 0.)] vR= tmp_out[:,2]*nu.cos(phi)+tmp_out[:,3]*nu.sin(phi) vT= tmp_out[:,3]*nu.cos(phi)-tmp_out[:,2]*nu.sin(phi) out= nu.zeros((len(t),4)) out[:,0]= R out[:,1]= vR out[:,2]= vT out[:,3]= phi msg= 0 elif method.lower() == 'leapfrog_c' or method.lower() == 'rk4_c' \ or method.lower() == 'rk6_c' or method.lower() == 'symplec4_c' \ or method.lower() == 'symplec6_c' or method.lower() == 'dopr54_c': warnings.warn("Using C implementation to integrate orbits",galpyWarning) #go to the rectangular frame this_vxvv= nu.array([vxvv[0]*nu.cos(vxvv[3]), vxvv[0]*nu.sin(vxvv[3]), vxvv[1]*nu.cos(vxvv[3])-vxvv[2]*nu.sin(vxvv[3]), vxvv[2]*nu.cos(vxvv[3])+vxvv[1]*nu.sin(vxvv[3])]) #integrate tmp_out, msg= integratePlanarOrbit_c(pot,this_vxvv, t,method,dt=dt) #go back to the cylindrical frame R= nu.sqrt(tmp_out[:,0]**2.+tmp_out[:,1]**2.) phi= nu.arccos(tmp_out[:,0]/R) phi[(tmp_out[:,1] < 0.)]= 2.*nu.pi-phi[(tmp_out[:,1] < 0.)] vR= tmp_out[:,2]*nu.cos(phi)+tmp_out[:,3]*nu.sin(phi) vT= tmp_out[:,3]*nu.cos(phi)-tmp_out[:,2]*nu.sin(phi) out= nu.zeros((len(t),4)) out[:,0]= R out[:,1]= vR out[:,2]= vT out[:,3]= phi elif method.lower() == 'odeint': vphi= vxvv[2]/vxvv[0] init= [vxvv[0],vxvv[1],vxvv[3],vphi] intOut= integrate.odeint(_EOM,init,t,args=(pot,), rtol=10.**-8.)#,mxstep=100000000) out= nu.zeros((len(t),4)) out[:,0]= intOut[:,0] out[:,1]= intOut[:,1] out[:,3]= intOut[:,2] out[:,2]= out[:,0]*intOut[:,3] msg= 0 else: raise NotImplementedError("requested integration method does not exist") #post-process to remove negative radii neg_radii= (out[:,0] < 0.) out[neg_radii,0]= -out[neg_radii,0] out[neg_radii,3]+= m.pi _parse_warnmessage(msg) return (out,msg)
def _evaluate(self,*args,**kwargs): """ NAME: _evaluate PURPOSE: evaluate the actions (jr,lz,jz) INPUT: Either: a) R,vR,vT,z,vz b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well c= True/False; overrides the object's c= keyword to use C or not scipy.integrate.quadrature keywords OUTPUT: (jr,lz,jz) HISTORY: 2012-11-27 - Written - Bovy (IAS) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz R,vR,vT, z, vz= args elif len(args) == 6: #R,vR.vT, z, vz, phi R,vR,vT, z, vz, phi= args else: self._parse_eval_args(*args) R= self._eval_R vR= self._eval_vR vT= self._eval_vT z= self._eval_z vz= self._eval_vz if isinstance(R,float): R= nu.array([R]) vR= nu.array([vR]) vT= nu.array([vT]) z= nu.array([z]) vz= nu.array([vz]) Lz= R*vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0= nu.asarray(kwargs['u0']) else: E= nu.array([_evaluatePotentials(self._pot,R[ii],z[ii]) +vR[ii]**2./2.+vz[ii]**2./2.+vT[ii]**2./2. for ii in range(len(R))]) u0= actionAngleStaeckel_c.actionAngleStaeckel_calcu0(E,Lz, self._pot, self._delta)[0] kwargs.pop('u0',None) else: u0= None jr, jz, err= actionAngleStaeckel_c.actionAngleStaeckel_c(\ self._pot,self._delta,R,vR,vT,z,vz,u0=u0) if err == 0: return (jr,Lz,jz) else: #pragma: no cover raise RuntimeError("C-code for calculation actions failed; try with c=False") else: if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn("C module not used because potential does not have a C implementation",galpyWarning) kwargs.pop('c',None) if (len(args) == 5 or len(args) == 6) \ and isinstance(args[0],nu.ndarray): ojr= nu.zeros((len(args[0]))) olz= nu.zeros((len(args[0]))) ojz= nu.zeros((len(args[0]))) for ii in range(len(args[0])): if len(args) == 5: targs= (args[0][ii],args[1][ii],args[2][ii], args[3][ii],args[4][ii]) elif len(args) == 6: targs= (args[0][ii],args[1][ii],args[2][ii], args[3][ii],args[4][ii],args[5][ii]) tjr,tlz,tjz= self(*targs,**copy.copy(kwargs)) ojr[ii]= tjr ojz[ii]= tjz olz[ii]= tlz return (ojr,olz,ojz) else: #Set up the actionAngleStaeckelSingle object aASingle= actionAngleStaeckelSingle(*args,pot=self._pot, delta=self._delta) return (aASingle.JR(**copy.copy(kwargs)), aASingle._R*aASingle._vT, aASingle.Jz(**copy.copy(kwargs)))
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,phi (MUST HAVE PHI) b) Orbit instance: initial condition used if that's it, orbit(t) if there is a time given as well scipy.integrate.quadrature keywords OUTPUT: (jr,lz,jz,Omegar,Omegaphi,Omegaz,angler,anglephi,anglez) HISTORY: 2013-08-28 - Written - Bovy (IAS) """ if ((self._c and not ('c' in kwargs and not kwargs['c']))\ or (ext_loaded and (('c' in kwargs and kwargs['c'])))) \ and _check_c(self._pot): if len(args) == 5: #R,vR.vT, z, vz pragma: no cover raise IOError("Must specify phi") elif len(args) == 6: #R,vR.vT, z, vz, phi R, vR, vT, z, vz, phi = args else: meta = actionAngle(*args) R = meta._R vR = meta._vR vT = meta._vT z = meta._z vz = meta._vz phi = meta._phi if isinstance(R, float): R = nu.array([R]) vR = nu.array([vR]) vT = nu.array([vT]) z = nu.array([z]) vz = nu.array([vz]) phi = nu.array([phi]) Lz = R * vT if self._useu0: #First calculate u0 if 'u0' in kwargs: u0 = nu.asarray(kwargs['u0']) else: E = nu.array([ evaluatePotentials(R[ii], z[ii], self._pot) + vR[ii]**2. / 2. + vz[ii]**2. / 2. + vT[ii]**2. / 2. for ii in range(len(R)) ]) u0 = actionAngleStaeckel_c.actionAngleStaeckel_calcu0( E, Lz, self._pot, self._delta)[0] kwargs.pop('u0', None) else: u0 = None jr, jz, Omegar, Omegaphi, Omegaz, angler, anglephi,anglez, err= actionAngleStaeckel_c.actionAngleFreqAngleStaeckel_c(\ self._pot,self._delta,R,vR,vT,z,vz,phi,u0=u0) # Adjustements for close-to-circular orbits indx = nu.isnan(Omegar) * (jr < 10.**-3.) + nu.isnan(Omegaz) * ( jz < 10.**-3. ) #Close-to-circular and close-to-the-plane orbits if nu.sum(indx) > 0: Omegar[indx] = [epifreq(self._pot, r) for r in R[indx]] Omegaphi[indx] = [omegac(self._pot, r) for r in R[indx]] Omegaz[indx] = [verticalfreq(self._pot, r) for r in R[indx]] if err == 0: return (jr, Lz, jz, Omegar, Omegaphi, Omegaz, angler, anglephi, anglez) else: raise RuntimeError( "C-code for calculation actions failed; try with c=False" ) #pragma: no cover else: #pragma: no cover if 'c' in kwargs and kwargs['c'] and not self._c: #pragma: no cover warnings.warn( "C module not used because potential does not have a C implementation", galpyWarning) raise NotImplementedError( "actionsFreqs with c=False not implemented")
def _integrateOrbit_dxdv(vxvv, dxdv, pot, t, method, rectIn, rectOut): """ NAME: _integrateOrbit_dxdv PURPOSE: integrate an orbit and area of phase space in a Phi(R) potential in the (R,phi)-plane INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT,phi]; vR outward! dxdv - difference to integrate [dR,dvR,dvT,dphi] pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' rectIn= (False) if True, input dxdv is in rectangular coordinates rectOut= (False) if True, output dxdv (that in orbit_dxdv) is in rectangular coordinates OUTPUT: [:,8] array of [R,vR,vT,phi,dR,dvR,dvT,dphi] at each t error message from integrator HISTORY: 2010-10-17 - Written - Bovy (IAS) """ #First check that the potential has C if '_c' in method: allHasC = _check_c(pot) and _check_c(pot, dxdv=True) if not allHasC and not 'leapfrog' in method and not 'symplec' in method: method = 'odeint' warnings.warn( "Using odeint because not all used potential have adequate C implementations to integrate phase-space volumes", galpyWarning) #go to the rectangular frame this_vxvv = nu.array([ vxvv[0] * nu.cos(vxvv[3]), vxvv[0] * nu.sin(vxvv[3]), vxvv[1] * nu.cos(vxvv[3]) - vxvv[2] * nu.sin(vxvv[3]), vxvv[2] * nu.cos(vxvv[3]) + vxvv[1] * nu.sin(vxvv[3]) ]) if not rectIn: this_dxdv = nu.array([ nu.cos(vxvv[3]) * dxdv[0] - vxvv[0] * nu.sin(vxvv[3]) * dxdv[3], nu.sin(vxvv[3]) * dxdv[0] + vxvv[0] * nu.cos(vxvv[3]) * dxdv[3], -(vxvv[1] * nu.sin(vxvv[3]) + vxvv[2] * nu.cos(vxvv[3])) * dxdv[3] + nu.cos(vxvv[3]) * dxdv[1] - nu.sin(vxvv[3]) * dxdv[2], (vxvv[1] * nu.cos(vxvv[3]) - vxvv[2] * nu.sin(vxvv[3])) * dxdv[3] + nu.sin(vxvv[3]) * dxdv[1] + nu.cos(vxvv[3]) * dxdv[2] ]) else: this_dxdv = dxdv if 'leapfrog' in method.lower() or 'symplec' in method.lower(): raise TypeError( 'Symplectic integration for phase-space volume is not possible') elif method.lower() == 'rk4_c' or method.lower() == 'rk6_c' \ or method.lower() == 'dopr54_c': warnings.warn("Using C implementation to integrate orbits", galpyWarningVerbose) #integrate tmp_out, msg = integratePlanarOrbit_dxdv_c(pot, this_vxvv, this_dxdv, t, method) elif method.lower() == 'odeint': init = [ this_vxvv[0], this_vxvv[1], this_vxvv[2], this_vxvv[3], this_dxdv[0], this_dxdv[1], this_dxdv[2], this_dxdv[3] ] #integrate tmp_out = integrate.odeint(_EOM_dxdv, init, t, args=(pot, ), rtol=10.**-8.) #,mxstep=100000000) msg = 0 else: raise NotImplementedError( "requested integration method does not exist") #go back to the cylindrical frame R = nu.sqrt(tmp_out[:, 0]**2. + tmp_out[:, 1]**2.) phi = nu.arccos(tmp_out[:, 0] / R) phi[(tmp_out[:, 1] < 0.)] = 2. * nu.pi - phi[(tmp_out[:, 1] < 0.)] vR = tmp_out[:, 2] * nu.cos(phi) + tmp_out[:, 3] * nu.sin(phi) vT = tmp_out[:, 3] * nu.cos(phi) - tmp_out[:, 2] * nu.sin(phi) cp = nu.cos(phi) sp = nu.sin(phi) dR = cp * tmp_out[:, 4] + sp * tmp_out[:, 5] dphi = (cp * tmp_out[:, 5] - sp * tmp_out[:, 4]) / R dvR = cp * tmp_out[:, 6] + sp * tmp_out[:, 7] + vT * dphi dvT = cp * tmp_out[:, 7] - sp * tmp_out[:, 6] - vR * dphi out = nu.zeros((len(t), 8)) out[:, 0] = R out[:, 1] = vR out[:, 2] = vT out[:, 3] = phi if rectOut: out[:, 4:] = tmp_out[:, 4:] else: out[:, 4] = dR out[:, 7] = dphi out[:, 5] = dvR out[:, 6] = dvT _parse_warnmessage(msg) return (out, msg)
def _integrateRZOrbit(vxvv, pot, t, method, dt): """ NAME: _integrateRZOrbit PURPOSE: integrate an orbit in a Phi(R,z) potential in the (R,z) plane INPUT: vxvv - array with the initial conditions stacked like [R,vR,vT,z,vz]; vR outward! pot - Potential instance t - list of times at which to output (0 has to be in this!) method - 'odeint' or 'leapfrog' dt - if set, force the integrator to use this basic stepsize; must be an integer divisor of output stepsize OUTPUT: [:,5] array of [R,vR,vT,z,vz] at each t HISTORY: 2010-04-16 - Written - Bovy (NYU) """ #First check that the potential has C if '_c' in method: if not ext_loaded or not _check_c(pot): if ('leapfrog' in method or 'symplec' in method): method = 'leapfrog' else: method = 'odeint' if not ext_loaded: # pragma: no cover warnings.warn( "Cannot use C integration because C extension not loaded (using %s instead)" % (method), galpyWarning) else: warnings.warn( "Cannot use C integration because some of the potentials are not implemented in C (using %s instead)" % (method), galpyWarning) if method.lower() == 'leapfrog' \ or method.lower() == 'leapfrog_c' or method.lower() == 'rk4_c' \ or method.lower() == 'rk6_c' or method.lower() == 'symplec4_c' \ or method.lower() == 'symplec6_c' or method.lower() == 'dopr54_c': #We hack this by upgrading to a FullOrbit this_vxvv = nu.zeros(len(vxvv) + 1) this_vxvv[0:len(vxvv)] = vxvv tmp_out = _integrateFullOrbit(this_vxvv, pot, t, method, dt) #tmp_out is (nt,6) out = tmp_out[:, 0:5] elif method.lower() == 'odeint': l = vxvv[0] * vxvv[2] l2 = l**2. init = [vxvv[0], vxvv[1], vxvv[3], vxvv[4]] intOut = integrate.odeint(_RZEOM, init, t, args=(pot, l2), rtol=10.**-8.) #,mxstep=100000000) out = nu.zeros((len(t), 5)) out[:, 0] = intOut[:, 0] out[:, 1] = intOut[:, 1] out[:, 3] = intOut[:, 2] out[:, 4] = intOut[:, 3] out[:, 2] = l / out[:, 0] #post-process to remove negative radii neg_radii = (out[:, 0] < 0.) out[neg_radii, 0] = -out[neg_radii, 0] return out