Source code for galpy.potential.linearPotential

from __future__ import division, print_function

import os, os.path
import copy
import pickle
import numpy
from ..util import bovy_plot as plot
from ..util import config
from .Potential import PotentialError, flatten
from ..util.bovy_conversion import physical_conversion,\
    potential_physical_input, physical_compatible
_APY_LOADED= True
try:
    from astropy import units
except ImportError:
    _APY_LOADED= False
class linearPotential(object):
    """Class representing 1D potentials"""
    def __init__(self,amp=1.,ro=None,vo=None):
        self._amp= amp
        self.dim= 1
        self.isRZ= False
        self.hasC= False
        self.hasC_dxdv= False
        self.hasC_dens= False
        # Parse ro and vo
        if ro is None:
            self._ro= config.__config__.getfloat('normalization','ro')
            self._roSet= False
        else:
            if _APY_LOADED and isinstance(ro,units.Quantity):
                ro= ro.to(units.kpc).value
            self._ro= ro
            self._roSet= True
        if vo is None:
            self._vo= config.__config__.getfloat('normalization','vo')
            self._voSet= False
        else:
            if _APY_LOADED and isinstance(vo,units.Quantity):
                vo= vo.to(units.km/units.s).value
            self._vo= vo
            self._voSet= True
        return None

[docs] def __mul__(self,b): """ NAME: __mul__ PURPOSE: Multiply a linearPotential's amplitude by a number INPUT: b - number OUTPUT: New instance with amplitude = (old amplitude) x b HISTORY: 2019-01-27 - Written - Bovy (UofT) """ if not isinstance(b,(int,float)): raise TypeError("Can only multiply a planarPotential instance with a number") out= copy.deepcopy(self) out._amp*= b return out
# Similar functions __rmul__= __mul__ def __div__(self,b): return self.__mul__(1./b) __truediv__= __div__
[docs] def __add__(self,b): """ NAME: __add__ PURPOSE: Add linearPotential instances together to create a multi-component potential (e.g., pot= pot1+pot2+pot3) INPUT: b - linearPotential instance or a list thereof OUTPUT: List of linearPotential instances that represents the combined potential HISTORY: 2019-01-27 - Written - Bovy (UofT) """ from ..potential import flatten as flatten_pot if not isinstance(flatten_pot([b])[0],linearPotential): raise TypeError("""Can only combine galpy linearPotential""" """ objects with """ """other such objects or lists thereof""") assert physical_compatible(self,b), \ """Physical unit conversion parameters (ro,vo) are not """\ """compatible between potentials to be combined""" if isinstance(b,list): return [self]+b else: return [self,b]
# Define separately to keep order def __radd__(self,b): from ..potential import flatten as flatten_pot if not isinstance(flatten_pot([b])[0],linearPotential): raise TypeError("""Can only combine galpy linearPotential""" """ objects with """ """other such objects or lists thereof""") assert physical_compatible(self,b), \ """Physical unit conversion parameters (ro,vo) are not """\ """compatible between potentials to be combined""" # If we get here, b has to be a list return b+[self]
[docs] def turn_physical_off(self): """ NAME: turn_physical_off PURPOSE: turn off automatic returning of outputs in physical units INPUT: (none) OUTPUT: (none) HISTORY: 2016-01-30 - Written - Bovy (UofT) """ self._roSet= False self._voSet= False return None
[docs] def turn_physical_on(self,ro=None,vo=None): """ NAME: turn_physical_on PURPOSE: turn on automatic returning of outputs in physical units INPUT: ro= reference distance (kpc; can be Quantity) vo= reference velocity (km/s; can be Quantity) OUTPUT: (none) HISTORY: 2016-01-30 - Written - Bovy (UofT) 2020-04-22 - Don't turn on a parameter when it is False - Bovy (UofT) """ if not ro is False: self._roSet= True if not vo is False: self._voSet= True if not ro is None and ro: if _APY_LOADED and isinstance(ro,units.Quantity): ro= ro.to(units.kpc).value self._ro= ro if not vo is None and vo: if _APY_LOADED and isinstance(vo,units.Quantity): vo= vo.to(units.km/units.s).value self._vo= vo return None
[docs] @potential_physical_input @physical_conversion('energy',pop=True) def __call__(self,x,t=0.): """ NAME: __call__ PURPOSE: evaluate the potential INPUT: x - position (can be Quantity) t= time (optional; can be Quantity) OUTPUT: Phi(x,t) HISTORY: 2010-07-12 - Written - Bovy (NYU) """ return self._call_nodecorator(x,t=t)
def _call_nodecorator(self,x,t=0.): # Separate, so it can be used during orbit integration try: return self._amp*self._evaluate(x,t=t) except AttributeError: #pragma: no cover raise PotentialError("'_evaluate' function not implemented for this potential")
[docs] @potential_physical_input @physical_conversion('force',pop=True) def force(self,x,t=0.): """ NAME: force PURPOSE: evaluate the force INPUT: x - position (can be Quantity) t= time (optional; can be Quantity) OUTPUT: F(x,t) HISTORY: 2010-07-12 - Written - Bovy (NYU) """ return self._force_nodecorator(x,t=t)
def _force_nodecorator(self,x,t=0.): # Separate, so it can be used during orbit integration try: return self._amp*self._force(x,t=t) except AttributeError: #pragma: no cover raise PotentialError("'_force' function not implemented for this potential")
[docs] def plot(self,t=0.,min=-15.,max=15,ns=21,savefilename=None): """ NAME: plot PURPOSE: plot the potential INPUT: t - time to evaluate the potential at min - minimum x max - maximum x ns - grid in x savefilename - save to or restore from this savefile (pickle) OUTPUT: plot to output device HISTORY: 2010-07-13 - Written - Bovy (NYU) """ if not savefilename == None and os.path.exists(savefilename): print("Restoring savefile "+savefilename+" ...") savefile= open(savefilename,'rb') potx= pickle.load(savefile) xs= pickle.load(savefile) savefile.close() else: xs= numpy.linspace(min,max,ns) potx= numpy.zeros(ns) for ii in range(ns): potx[ii]= self._evaluate(xs[ii],t=t) if not savefilename == None: print("Writing savefile "+savefilename+" ...") savefile= open(savefilename,'wb') pickle.dump(potx,savefile) pickle.dump(xs,savefile) savefile.close() return plot.bovy_plot(xs,potx, xlabel=r"$x/x_0$",ylabel=r"$\Phi(x)$", xrange=[min,max])
[docs]@potential_physical_input @physical_conversion('energy',pop=True) def evaluatelinearPotentials(Pot,x,t=0.): """ NAME: evaluatelinearPotentials PURPOSE: evaluate the sum of a list of potentials INPUT: Pot - (list of) linearPotential instance(s) x - evaluate potentials at this position (can be Quantity) t - time to evaluate at (can be Quantity) OUTPUT: pot(x,t) HISTORY: 2010-07-13 - Written - Bovy (NYU) """ return _evaluatelinearPotentials(Pot,x,t=t)
def _evaluatelinearPotentials(Pot,x,t=0.): """Raw, undecorated function for internal use""" if isinstance(Pot,list): sum= 0. for pot in Pot: sum+= pot._call_nodecorator(x,t=t) return sum elif isinstance(Pot,linearPotential): return Pot._call_nodecorator(x,t=t) else: #pragma: no cover raise PotentialError("Input to 'evaluatelinearPotentials' is neither a linearPotential-instance or a list of such instances")
[docs]@potential_physical_input @physical_conversion('force',pop=True) def evaluatelinearForces(Pot,x,t=0.): """ NAME: evaluatelinearForces PURPOSE: evaluate the forces due to a list of potentials INPUT: Pot - (list of) linearPotential instance(s) x - evaluate forces at this position (can be Quantity) t - time to evaluate at (can be Quantity) OUTPUT: force(x,t) HISTORY: 2010-07-13 - Written - Bovy (NYU) """ return _evaluatelinearForces(Pot,x,t=t)
def _evaluatelinearForces(Pot,x,t=0.): """Raw, undecorated function for internal use""" if isinstance(Pot,list): sum= 0. for pot in Pot: sum+= pot._force_nodecorator(x,t=t) return sum elif isinstance(Pot,linearPotential): return Pot._force_nodecorator(x,t=t) else: #pragma: no cover raise PotentialError("Input to 'evaluateForces' is neither a linearPotential-instance or a list of such instances")
[docs]def plotlinearPotentials(Pot,t=0.,min=-15.,max=15,ns=21,savefilename=None): """ NAME: plotlinearPotentials PURPOSE: plot a combination of potentials INPUT: t - time to evaluate potential at min - minimum x max - maximum x ns - grid in x savefilename - save to or restore from this savefile (pickle) OUTPUT: plot to output device HISTORY: 2010-07-13 - Written - Bovy (NYU) """ Pot= flatten(Pot) if not savefilename == None and os.path.exists(savefilename): print("Restoring savefile "+savefilename+" ...") savefile= open(savefilename,'rb') potx= pickle.load(savefile) xs= pickle.load(savefile) savefile.close() else: xs= numpy.linspace(min,max,ns) potx= numpy.zeros(ns) for ii in range(ns): potx[ii]= evaluatelinearPotentials(Pot,xs[ii],t=t) if not savefilename == None: print("Writing savefile "+savefilename+" ...") savefile= open(savefilename,'wb') pickle.dump(potx,savefile) pickle.dump(xs,savefile) savefile.close() return plot.bovy_plot(xs,potx, xlabel=r"$x/x_0$",ylabel=r"$\Phi(x)$", xrange=[min,max])