def test_meanjz(): #This is a *very* rough test against a rough estimate of the mean qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential,aA=aAS,cutcounter=True) ldiff= numpy.log(qdf.meanjz(0.9,0.,mc=True))-2.*numpy.log(0.1)-0.2\ +numpy.log(verticalfreq(MWPotential,0.9)) #expect this to be smaller than the rough estimate, but not by more than an order of magnitude assert ldiff > -1. and ldiff < 0., 'meanjz is not what is expected' ldiff= numpy.log(qdf.meanjz(0.5,0.,mc=True))-2.*numpy.log(0.1)-1.0\ +numpy.log(verticalfreq(MWPotential,0.5)) assert ldiff > -1. and ldiff < 0., 'meanjz is not what is expected' return None
def verticalfreq(self,R): from galpy.potential import verticalfreq if self._interpverticalfreq: indx= (R >= self._rgrid[0])*(R <= self._rgrid[-1]) out= numpy.empty_like(R) if numpy.sum(indx) > 0: if self._logR: out[indx]= self._verticalfreqInterp(numpy.log(R[indx])) else: out[indx]= self._verticalfreqInterp(R[indx]) if numpy.sum(True^indx) > 0: out[True^indx]= verticalfreq(self._origPot,R[True^indx]) return out else: return verticalfreq(self._origPot,R)
def verticalfreq(self,R): if self._interpverticalfreq: if self._logR: return self._verticalfreqInterp(numpy.log(R)) else: return self._verticalfreqInterp(R) else: from galpy.potential import verticalfreq return verticalfreq(self._origPot,R)
def test_actionAngleTorus_basic_freqs(): from galpy.actionAngle import actionAngleTorus from galpy.potential import epifreq, omegac, verticalfreq, rl, \ JaffePotential, PowerSphericalPotential, HernquistPotential tol= -3. jr= 10.**-6. jz= 10.**-6. jp= JaffePotential(normalize=1.) aAT= actionAngleTorus(pot=jp) # at Lz=1 jphi= 1. om= aAT.Freqs(jr,jphi,jz) assert numpy.fabs((om[0]-epifreq(jp,rl(jp,jphi)))/om[0]) < 10.**tol, \ 'Close-to-circular orbit does not have Or=kappa for actionAngleTorus' assert numpy.fabs((om[1]-omegac(jp,rl(jp,jphi)))/om[1]) < 10.**tol, \ 'Close-to-circular orbit does not have Ophi=omega for actionAngleTorus' assert numpy.fabs((om[2]-verticalfreq(jp,rl(jp,jphi)))/om[2]) < 10.**tol, \ 'Close-to-circular orbit does not have Oz=nu for actionAngleTorus' # at Lz=1.5, w/ different potential pp= PowerSphericalPotential(normalize=1.) aAT= actionAngleTorus(pot=pp) jphi= 1.5 om= aAT.Freqs(jr,jphi,jz) assert numpy.fabs((om[0]-epifreq(pp,rl(pp,jphi)))/om[0]) < 10.**tol, \ 'Close-to-circular orbit does not have Or=kappa for actionAngleTorus' assert numpy.fabs((om[1]-omegac(pp,rl(pp,jphi)))/om[1]) < 10.**tol, \ 'Close-to-circular orbit does not have Ophi=omega for actionAngleTorus' assert numpy.fabs((om[2]-verticalfreq(pp,rl(pp,jphi)))/om[2]) < 10.**tol, \ 'Close-to-circular orbit does not have Oz=nu for actionAngleTorus' # at Lz=0.5, w/ different potential tol= -2.5 # appears more difficult hp= HernquistPotential(normalize=1.) aAT= actionAngleTorus(pot=hp) jphi= 0.5 om= aAT.Freqs(jr,jphi,jz) assert numpy.fabs((om[0]-epifreq(hp,rl(hp,jphi)))/om[0]) < 10.**tol, \ 'Close-to-circular orbit does not have Or=kappa for actionAngleTorus' assert numpy.fabs((om[1]-omegac(hp,rl(hp,jphi)))/om[1]) < 10.**tol, \ 'Close-to-circular orbit does not have Ophi=omega for actionAngleTorus' assert numpy.fabs((om[2]-verticalfreq(hp,rl(hp,jphi)))/om[2]) < 10.**tol, \ 'Close-to-circular orbit does not have Oz=nu for actionAngleTorus' return None
def test_call_diffinoutputs(): qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential,aA=aAS,cutcounter=True) #when specifying rg etc., first get these from a previous output val, trg, tkappa, tnu, tOmega= qdf((0.03,0.9,0.02),_return_freqs=True) #First check that just supplying these again works assert numpy.fabs(val-qdf((0.03,0.9,0.02),rg=trg,kappa=tkappa,nu=tnu, Omega=tOmega)) < 10.**-8., 'qdf calls w/ rg, and frequencies specified and w/ not specified do not agrees' #Also calculate the frequencies assert numpy.fabs(val-qdf((0.03,0.9,0.02),rg=trg, kappa=epifreq(MWPotential,trg), nu=verticalfreq(MWPotential,trg), Omega=omegac(MWPotential,trg))) < 10.**-8., 'qdf calls w/ rg, and frequencies specified and w/ not specified do not agrees' #Also test _return_actions val, jr,lz,jz= qdf(0.9,0.1,0.95,0.1,0.08,_return_actions=True) assert numpy.fabs(val-qdf((jr,lz,jz))) < 10.**-8., 'qdf call w/ R,vR,... and actions specified do not agree' acs= aAS(0.9,0.1,0.95,0.1,0.08) assert numpy.fabs(acs[0]-jr) < 10.**-8., 'direct calculation of jr and that returned from qdf.__call__ does not agree' assert numpy.fabs(acs[1]-lz) < 10.**-8., 'direct calculation of lz and that returned from qdf.__call__ does not agree' assert numpy.fabs(acs[2]-jz) < 10.**-8., 'direct calculation of jz and that returned from qdf.__call__ does not agree' #Test unbound orbits #Find unbound orbit, new qdf s.t. we can get UnboundError (only with taAS= actionAngleStaeckel(pot=MWPotential,c=False,delta=0.5) qdfnc= quasiisothermaldf(1./4.,0.2,0.1,1.,1., pot=MWPotential, aA=taAS, cutcounter=True) from galpy.actionAngle import UnboundError try: acs= taAS(0.9,10.,-20.,0.1,10.) except UnboundError: pass else: print(acs) raise AssertionError('Test orbit in qdf that is supposed to be unbound is not') assert qdfnc(0.9,10.,-20.,0.1,10.) < 10.**-10., 'unbound orbit does not return qdf equal to zero' #Test negative lz assert qdf((0.03,-0.1,0.02)) < 10.**-8., 'qdf w/ cutcounter=True and negative lz does not return 0' assert qdf((0.03,-0.1,0.02),log=True) <= numpy.finfo(numpy.dtype(numpy.float64)).min+1., 'qdf w/ cutcounter=True and negative lz does not return 0' #Test func val= qdf((0.03,0.9,0.02)) fval= qdf((0.03,0.9,0.02),func=lambda x,y,z: numpy.sin(x)*numpy.cos(y)\ *numpy.exp(z)) assert numpy.fabs(val*numpy.sin(0.03)*numpy.cos(0.9)*numpy.exp(0.02)- fval) < 10.**-8, 'qdf __call__ w/ func does not work as expected' lfval= qdf((0.03,0.9,0.02),func=lambda x,y,z: numpy.sin(x)*numpy.cos(y)\ *numpy.exp(z),log=True) assert numpy.fabs(numpy.log(val)+numpy.log(numpy.sin(0.03)\ *numpy.cos(0.9)\ *numpy.exp(0.02))- lfval) < 10.**-8, 'qdf __call__ w/ func does not work as expected' return None
def _calc_verticalfreq(self, r): """ NAME: _calc_verticalfreq PURPOSE: calculate the vertical frequency at r INPUT: r - radius OUTPUT: nu HISTORY: 2012-07-25 - Written - Bovy (IAS@MPIA) NOTE: takes about 0.05 ms for a Miyamoto-Nagai potential """ return potential.verticalfreq(self._pot, r)
def scale_height(R, R0, tau): """ Scale height in function of the mean vertical action and the vertical frequency as a function of birth radius, current radius and time. For isothermal sech2 distribution Arguments: R = present day Galctocentric radius [kpc] R0 = birth Galactocentric radius [kpc] t = stellar age [Gyr] Returns hz = the scale-height [kpc] 2019-01-19 frankel """ jz = vertical_action((R + R0) / 2., tau) nu = verticalfreq(pot, R / _REFR0) * _REFV0 / _REFR0 hz = np.sqrt(2 * jz / nu) return hz
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 _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 __init__(self, RZPot=None,rgrid=(numpy.log(0.01),numpy.log(20.),101), zgrid=(0.,1.,101),logR=True, interpPot=False,interpRforce=False,interpzforce=False, interpDens=False, interpvcirc=False, interpdvcircdr=False, interpepifreq=False,interpverticalfreq=False, ro=None,vo=None, use_c=False,enable_c=False,zsym=True, numcores=None): """ NAME: __init__ PURPOSE: Initialize an interpRZPotential instance INPUT: RZPot - RZPotential to be interpolated rgrid - R grid to be given to linspace as in rs= linspace(*rgrid) zgrid - z grid to be given to linspace as in zs= linspace(*zgrid) logR - if True, rgrid is in the log of R so logrs= linspace(*rgrid) interpPot, interpRforce, interpzforce, interpDens,interpvcirc, interpepifreq, interpverticalfreq, interpdvcircdr= if True, interpolate these functions use_c= use C to speed up the calculation of the grid enable_c= enable use of C for interpolations zsym= if True (default), the potential is assumed to be symmetric around z=0 (so you can use, e.g., zgrid=(0.,1.,101)). numcores= if set to an integer, use this many cores (only used for vcirc, dvcircdR, epifreq, and verticalfreq; NOT NECESSARILY FASTER, TIME TO MAKE SURE) ro=, vo= distance and velocity scales for translation into internal units (default from configuration file) OUTPUT: instance HISTORY: 2010-07-21 - Written - Bovy (NYU) 2013-01-24 - Started with new implementation - Bovy (IAS) """ if isinstance(RZPot,interpRZPotential): from galpy.potential import PotentialError raise PotentialError('Cannot setup interpRZPotential with another interpRZPotential') # Propagate ro and vo roSet= True voSet= True if ro is None: if isinstance(RZPot,list): ro= RZPot[0]._ro roSet= RZPot[0]._roSet else: ro= RZPot._ro roSet= RZPot._roSet if vo is None: if isinstance(RZPot,list): vo= RZPot[0]._vo voSet= RZPot[0]._voSet else: vo= RZPot._vo voSet= RZPot._voSet Potential.__init__(self,amp=1.,ro=ro,vo=vo) # Turn off physical if it hadn't been on if not roSet: self._roSet= False if not voSet: self._voSet= False self._origPot= RZPot self._rgrid= numpy.linspace(*rgrid) self._logR= logR if self._logR: self._rgrid= numpy.exp(self._rgrid) self._logrgrid= numpy.log(self._rgrid) self._zgrid= numpy.linspace(*zgrid) self._interpPot= interpPot self._interpRforce= interpRforce self._interpzforce= interpzforce self._interpDens= interpDens self._interpvcirc= interpvcirc self._interpdvcircdr= interpdvcircdr self._interpepifreq= interpepifreq self._interpverticalfreq= interpverticalfreq self._enable_c= enable_c*ext_loaded self.hasC= self._enable_c self._zsym= zsym if interpPot: if use_c*ext_loaded: self._potGrid, err= calc_potential_c(self._origPot,self._rgrid,self._zgrid) else: from galpy.potential import evaluatePotentials potGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): potGrid[ii,jj]= evaluatePotentials(self._origPot,self._rgrid[ii],self._zgrid[jj]) self._potGrid= potGrid if self._logR: self._potInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, self._potGrid, kx=3,ky=3,s=0.) else: self._potInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, self._potGrid, kx=3,ky=3,s=0.) if enable_c*ext_loaded: self._potGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._potGrid) if interpRforce: if use_c*ext_loaded: self._rforceGrid, err= calc_potential_c(self._origPot,self._rgrid,self._zgrid,rforce=True) else: from galpy.potential import evaluateRforces rforceGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): rforceGrid[ii,jj]= evaluateRforces(self._origPot,self._rgrid[ii],self._zgrid[jj]) self._rforceGrid= rforceGrid if self._logR: self._rforceInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, self._rforceGrid, kx=3,ky=3,s=0.) else: self._rforceInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, self._rforceGrid, kx=3,ky=3,s=0.) if enable_c*ext_loaded: self._rforceGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._rforceGrid) if interpzforce: if use_c*ext_loaded: self._zforceGrid, err= calc_potential_c(self._origPot,self._rgrid,self._zgrid,zforce=True) else: from galpy.potential import evaluatezforces zforceGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): zforceGrid[ii,jj]= evaluatezforces(self._origPot,self._rgrid[ii],self._zgrid[jj]) self._zforceGrid= zforceGrid if self._logR: self._zforceInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, self._zforceGrid, kx=3,ky=3,s=0.) else: self._zforceInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, self._zforceGrid, kx=3,ky=3,s=0.) if enable_c*ext_loaded: self._zforceGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._zforceGrid) if interpDens: from galpy.potential import evaluateDensities densGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): densGrid[ii,jj]= evaluateDensities(self._origPot,self._rgrid[ii],self._zgrid[jj]) self._densGrid= densGrid if self._logR: self._densInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, numpy.log(self._densGrid+10.**-10.), kx=3,ky=3,s=0.) else: self._densInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, numpy.log(self._densGrid+10.**-10.), kx=3,ky=3,s=0.) if interpvcirc: from galpy.potential import vcirc if not numcores is None: self._vcircGrid= multi.parallel_map((lambda x: vcirc(self._origPot,self._rgrid[x])), list(range(len(self._rgrid))),numcores=numcores) else: self._vcircGrid= numpy.array([vcirc(self._origPot,r) for r in self._rgrid]) if self._logR: self._vcircInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid,self._vcircGrid,k=3) else: self._vcircInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid,self._vcircGrid,k=3) if interpdvcircdr: from galpy.potential import dvcircdR if not numcores is None: self._dvcircdrGrid= multi.parallel_map((lambda x: dvcircdR(self._origPot,self._rgrid[x])), list(range(len(self._rgrid))),numcores=numcores) else: self._dvcircdrGrid= numpy.array([dvcircdR(self._origPot,r) for r in self._rgrid]) if self._logR: self._dvcircdrInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid,self._dvcircdrGrid,k=3) else: self._dvcircdrInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid,self._dvcircdrGrid,k=3) if interpepifreq: from galpy.potential import epifreq if not numcores is None: self._epifreqGrid= numpy.array(multi.parallel_map((lambda x: epifreq(self._origPot,self._rgrid[x])), list(range(len(self._rgrid))),numcores=numcores)) else: self._epifreqGrid= numpy.array([epifreq(self._origPot,r) for r in self._rgrid]) indx= True^numpy.isnan(self._epifreqGrid) if numpy.sum(indx) < 4: if self._logR: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid[indx],self._epifreqGrid[indx],k=1) else: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid[indx],self._epifreqGrid[indx],k=1) else: if self._logR: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid[indx],self._epifreqGrid[indx],k=3) else: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid[indx],self._epifreqGrid[indx],k=3) if interpverticalfreq: from galpy.potential import verticalfreq if not numcores is None: self._verticalfreqGrid= multi.parallel_map((lambda x: verticalfreq(self._origPot,self._rgrid[x])), list(range(len(self._rgrid))),numcores=numcores) else: self._verticalfreqGrid= numpy.array([verticalfreq(self._origPot,r) for r in self._rgrid]) if self._logR: self._verticalfreqInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid,self._verticalfreqGrid,k=3) else: self._verticalfreqInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid,self._verticalfreqGrid,k=3) return None
def change_Iso(self,df_stats,integ=False,tdep=False): rho0= df_stats[0] sig= df_stats[1] df= IsoDF(rho0,sig) try: freq= verticalfreq(self.pot,1.) except: freq= self.VertFreq() f0= df.calc_df(self.Jz[:,:,None]+self.deltaJ,freq) if integ: rho= simps(f0,self.v,axis=1) meanV= simps(f0*self.v[None,:],axis=1)/simps(f0,axis=1) else: rho= np.sum(f0,axis=1)*(self.v[1]-self.v[0]) meanV= np.sum(np.atleast_2d(self.v[None,:,None])*f0,axis=1)/f0.sum(axis=1) rawA= (rho-rho[::-1])/(rho+rho[::-1]) if tdep: try: if self.z0==None: nt= int(len(self.t)) zAA= np.tile(self.z,(nt,1)) zA= zAA[zAA>=0.] A= rawA[zAA>=0.] except: if (zsun=='fit') or (zsun=='mean'): nt= len(self.t) A= np.zeros([nt,self.znpt*2]) zf= np.zeros([nt,self.znpt*2]) for i,z0 in enumerate(self.z0): zs= 2.*z0-self.z zf[i]= np.sort(np.append(self.z,zs)) funcp= interp1d(self.z,np.log(rho[:,i]), fill_value='extrapolate',kind='cubic') p= np.exp(funcp(zf[i])) A[i]= (p-p[::-1])/(p+p[::-1]) A= A zA= zf-self.z0[:,None] zA= zA[zA>=0] else: print('Please choose fit, mean, or None as a method of finding zsun.') else: if self.z0==None: zAA= self.z zA= zAA[zAA>=0.] A= self.rawA[:,-1][zAA>=0] if self.z0.dtype=='float64': zs= 2.*self.z0-self.z zf= np.sort(np.append(self.z,zs)) funcp= interp1d(self.z,np.log(rho[:,0]), fill_value='extrapolate',kind='cubic') p= np.exp(funcp(zf)) A= (p-p[::-1])/(p+p[::-1]) zAA= zf-self.z0 zA= zAA[zAA>=0.] A= A[zAA>=0.] return f0, rho, meanV, zA, A
def calc_pert(self,dJ,t,df_stats,integ=False,rotFreq=1.,zsun='mean', tdep=False,method='slow'): self.rho0= df_stats[0] self.sig= df_stats[1] self.df= IsoDF(self.rho0,self.sig) try: freq= verticalfreq(self.pot,1.) except: freq= self.VertFreq() self.f0= self.df.calc_df(self.Jz+self.deltaJ,freq) if integ: self.rho= simps(self.f0,self.v,axis=1)[:,None] self.meanV= simps(self.f0*self.v[None,:],axis=1)/simps(self.f0,axis=1) else: self.rho= np.sum(self.f0,axis=1)*(self.v[1]-self.v[0]) self.meanV= np.sum(np.atleast_2d(self.v[None,:,None])*self.f0,axis=1)/self.f0.sum(axis=1) if zsun=='mean': #self.z0= -simps(self.rho.T*self.z,self.z) f= interp1d(np.cumsum(np.reshape(self.rho,self.znpt))/np.sum(self.rho),self.z) self.z0= f(0.5) elif zsun=='fit': if tdep: self.fit= np.array([self.calc_sechfit([self.rho[:,i],self.z],[np.log(np.max(self.rho[:,i])),0.,0.02]) for i in range(len(self.t))]) self.z0= -self.fit[:,1] else: self.fit= self.calc_sechfit([self.rho[:,0],self.z],[np.log(np.max(self.rho[:,0])),0.,0.02]) self.z0= -self.fit[1] elif zsun==None: self.z0=None else: print("""No method for finding zsun was specified, so it was assumed to be zero.\ Please specify either 'mean' or 'fit' to adjust for movement of the disc""") self.z0=0. self.rawA= (self.rho-self.rho[::-1])/(self.rho+self.rho[::-1]) #Calculate the asymmetry if tdep: try: if self.z0==None: nt= int(len(self.t)) zA= np.tile(self.z,(nt,1)).T self.zA= zA[int(self.znpt/2):] self.A= self.rawA[int(self.znpt/2):] except: if self.z0.dtype=='float64': nt= len(self.t) self.A= np.zeros([nt,self.znpt]) zf= np.zeros([nt,self.znpt]) self.zA= np.zeros([nt,self.znpt]) for i,z0 in enumerate(self.z0): zs= 2.*z0-self.z zf= np.sort(np.append(self.z,zs)) funcp= interp1d(self.z,np.log(self.rho[:,i]), fill_value='extrapolate',kind='cubic') p= np.exp(funcp(zf)) A= (p-p[::-1])/(p+p[::-1]) zA= zf-z0 self.zA[i]= zA[zA>=0.] self.A[i]= A[zA>=0.] else: print('Please choose fit, mean, or None as a method of finding zsun.') else: if self.z0==None: zA= self.z self.zA= zA[zA>=0.] self.A= self.rawA[:,-1][zA>=0] elif self.z0.dtype=='float64': zs= 2.*self.z0-self.z zf= np.sort(np.append(self.z,zs)) funcp= interp1d(self.z,np.log(self.rho[:,0]), fill_value='extrapolate',kind='cubic') p= np.exp(funcp(zf)) A= (p-p[::-1])/(p+p[::-1]) zA= zf-self.z0 self.zA= zA[zA>=0.] self.A= A[zA>=0.] return None
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 __init__(self, RZPot=None,rgrid=(0.01,2.,101),zgrid=(0.,0.2,101),logR=False, interpPot=False,interpRforce=False,interpzforce=False, interpDens=False, interpvcirc=False, interpdvcircdr=False, interpepifreq=False,interpverticalfreq=False, use_c=False,enable_c=False,zsym=True, numcores=None): """ NAME: __init__ PURPOSE: Initialize an interpRZPotential instance INPUT: RZPot - RZPotential to be interpolated rgrid - R grid to be given to linspace zgrid - z grid to be given to linspace logR - if True, rgrid is in the log of R interpPot, interpRfoce, interpzforce, interpDens,interpvcirc, interpeopifreq, interpverticalfreq, interpdvcircdr= if True, interpolate these functions use_c= use C to speed up the calculation enable_c= enable use of C for interpolations zsym= if True (default), the potential is assumed to be symmetric around z=0 (so you can use, e.g., zgrid=(0.,1.,101)). numcores= if set to an integer, use this many cores (only used for vcirc, dvcircdR, epifreq, and verticalfreq; NOT NECESSARILY FASTER, TIME TO MAKE SURE) OUTPUT: instance HISTORY: 2010-07-21 - Written - Bovy (NYU) 2013-01-24 - Started with new implementation - Bovy (IAS) """ Potential.__init__(self,amp=1.) self.hasC= True self._origPot= RZPot self._rgrid= numpy.linspace(*rgrid) self._logR= logR if self._logR: self._rgrid= numpy.exp(self._rgrid) self._logrgrid= numpy.log(self._rgrid) self._zgrid= numpy.linspace(*zgrid) self._interpPot= interpPot self._interpRforce= interpRforce self._interpzforce= interpzforce self._interpDens= interpDens self._interpvcirc= interpvcirc self._interpdvcircdr= interpdvcircdr self._interpepifreq= interpepifreq self._interpverticalfreq= interpverticalfreq self._enable_c= enable_c*ext_loaded self._zsym= zsym if interpPot: if use_c*ext_loaded: self._potGrid, err= calc_potential_c(self._origPot,self._rgrid,self._zgrid) else: from galpy.potential import evaluatePotentials potGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): potGrid[ii,jj]= evaluatePotentials(self._rgrid[ii],self._zgrid[jj],self._origPot) self._potGrid= potGrid if self._logR: self._potInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, self._potGrid, kx=3,ky=3,s=0.) else: self._potInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, self._potGrid, kx=3,ky=3,s=0.) if enable_c*ext_loaded: self._potGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._potGrid) if interpRforce: if use_c*ext_loaded: self._rforceGrid, err= calc_potential_c(self._origPot,self._rgrid,self._zgrid,rforce=True) else: from galpy.potential import evaluateRforces rforceGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): rforceGrid[ii,jj]= evaluateRforces(self._rgrid[ii],self._zgrid[jj],self._origPot) self._rforceGrid= rforceGrid if self._logR: self._rforceInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, self._rforceGrid, kx=3,ky=3,s=0.) else: self._rforceInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, self._rforceGrid, kx=3,ky=3,s=0.) if enable_c*ext_loaded: self._rforceGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._rforceGrid) if interpzforce: if use_c*ext_loaded: self._zforceGrid, err= calc_potential_c(self._origPot,self._rgrid,self._zgrid,zforce=True) else: from galpy.potential import evaluatezforces zforceGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): zforceGrid[ii,jj]= evaluatezforces(self._rgrid[ii],self._zgrid[jj],self._origPot) self._zforceGrid= zforceGrid if self._logR: self._zforceInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, self._zforceGrid, kx=3,ky=3,s=0.) else: self._zforceInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, self._zforceGrid, kx=3,ky=3,s=0.) if enable_c*ext_loaded: self._zforceGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._zforceGrid) if interpDens: if False: raise NotImplementedError("Using C to calculate an interpolation grid for the density is not supported currently") self._densGrid, err= calc_dens_c(self._origPot,self._rgrid,self._zgrid) else: from galpy.potential import evaluateDensities densGrid= numpy.zeros((len(self._rgrid),len(self._zgrid))) for ii in range(len(self._rgrid)): for jj in range(len(self._zgrid)): densGrid[ii,jj]= evaluateDensities(self._rgrid[ii],self._zgrid[jj],self._origPot) self._densGrid= densGrid if self._logR: self._densInterp= interpolate.RectBivariateSpline(self._logrgrid, self._zgrid, numpy.log(self._densGrid+10.**-10.), kx=3,ky=3,s=0.) else: self._densInterp= interpolate.RectBivariateSpline(self._rgrid, self._zgrid, numpy.log(self._densGrid+10.**-10.), kx=3,ky=3,s=0.) if False: self._densGrid_splinecoeffs= calc_2dsplinecoeffs_c(self._densGrid) if interpvcirc: from galpy.potential import vcirc if not numcores is None: self._vcircGrid= multi.parallel_map((lambda x: vcirc(self._origPot,self._rgrid[x])), range(len(self._rgrid)),numcores=numcores) else: self._vcircGrid= numpy.array([vcirc(self._origPot,r) for r in self._rgrid]) if self._logR: self._vcircInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid,self._vcircGrid,k=3) else: self._vcircInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid,self._vcircGrid,k=3) if interpdvcircdr: from galpy.potential import dvcircdR if not numcores is None: self._dvcircdrGrid= multi.parallel_map((lambda x: dvcircdR(self._origPot,self._rgrid[x])), range(len(self._rgrid)),numcores=numcores) else: self._dvcircdrGrid= numpy.array([dvcircdR(self._origPot,r) for r in self._rgrid]) if self._logR: self._dvcircdrInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid,self._dvcircdrGrid,k=3) else: self._dvcircdrInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid,self._dvcircdrGrid,k=3) if interpepifreq: from galpy.potential import epifreq if not numcores is None: self._epifreqGrid= multi.parallel_map((lambda x: epifreq(self._origPot,self._rgrid[x])), range(len(self._rgrid)),numcores=numcores) else: self._epifreqGrid= numpy.array([epifreq(self._origPot,r) for r in self._rgrid]) indx= True-numpy.isnan(self._epifreqGrid) if numpy.sum(indx) < 4: if self._logR: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid[indx],self._epifreqGrid[indx],k=1) else: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid[indx],self._epifreqGrid[indx],k=1) else: if self._logR: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid[indx],self._epifreqGrid[indx],k=3) else: self._epifreqInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid[indx],self._epifreqGrid[indx],k=3) if interpverticalfreq: from galpy.potential import verticalfreq if not numcores is None: self._verticalfreqGrid= multi.parallel_map((lambda x: verticalfreq(self._origPot,self._rgrid[x])), range(len(self._rgrid)),numcores=numcores) else: self._verticalfreqGrid= numpy.array([verticalfreq(self._origPot,r) for r in self._rgrid]) if self._logR: self._verticalfreqInterp= interpolate.InterpolatedUnivariateSpline(self._logrgrid,self._verticalfreqGrid,k=3) else: self._verticalfreqInterp= interpolate.InterpolatedUnivariateSpline(self._rgrid,self._verticalfreqGrid,k=3) 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,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")